scimapper 1.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gustavo Andrés Futo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,252 @@
1
+ Metadata-Version: 2.4
2
+ Name: scimapper
3
+ Version: 1.0.1
4
+ Summary: An automated scientific mapping and systematic literature review framework with dense semantic clustering and PRISMA 2020 compliance.
5
+ Author-email: Gustavo Andrés Futo <gustavoandresfu@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/gustavoandresfu/SciMapper
8
+ Project-URL: Bug Tracker, https://github.com/gustavoandresfu/SciMapper/issues
9
+ Keywords: systematic-literature-review,systematic-mapping-study,scimapper,scientific-mapping,topic-modeling,sentence-transformers,bertopic,prisma-2020,openalex,evidence-synthesis,nlp
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Classifier: Intended Audience :: Science/Research
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
21
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
22
+ Provides-Extra: web
23
+ Requires-Dist: streamlit>=1.30.0; extra == "web"
24
+ Provides-Extra: dependencies
25
+ Requires-Dist: requests>=2.28.0; extra == "dependencies"
26
+ Requires-Dist: pandas>=1.5.0; extra == "dependencies"
27
+ Requires-Dist: numpy>=1.23.0; extra == "dependencies"
28
+ Requires-Dist: scikit-learn>=1.2.0; extra == "dependencies"
29
+ Requires-Dist: scipy>=1.10.0; extra == "dependencies"
30
+ Requires-Dist: sentence-transformers>=2.2.0; extra == "dependencies"
31
+ Requires-Dist: torch>=2.0.0; extra == "dependencies"
32
+ Requires-Dist: plotly>=5.13.0; extra == "dependencies"
33
+ Requires-Dist: python-docx>=0.8.11; extra == "dependencies"
34
+ Requires-Dist: tqdm>=4.65.0; extra == "dependencies"
35
+ Dynamic: license-file
36
+
37
+ <div align="center">
38
+
39
+ # 🚀 SciMapper
40
+ ### Automated Scientific Mapping & Systematic Literature Reviews with Dense Semantic Clustering
41
+
42
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg?logo=python&logoColor=white)](https://www.python.org/)
43
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44
+ [![PRISMA 2020](https://img.shields.io/badge/PRISMA-2020%20Compliant-green.svg)](https://www.prisma-statement.org/)
45
+ [![OpenAlex API](https://img.shields.io/badge/Data%20Source-OpenAlex%20API-orange.svg)](https://openalex.org/)
46
+ [![NLP Engine](https://img.shields.io/badge/NLP-Sentence--Transformers-purple.svg)](https://www.sbert.net/)
47
+
48
+ **An end-to-end, domain-agnostic framework designed to conduct reproducible Systematic Literature Reviews (SLR) and Systematic Mapping Studies (SMS).**
49
+ It automates academic corpus harvesting, deduplication, dense semantic embedding, unsupervised clustering, taxonomic discovery, interactive 2D cartography, and manuscript drafting—while keeping **researchers firmly in the loop**.
50
+
51
+ 🌐 **Languages:** **English** • [Español (Guía en Castellano)](README_ES.md)
52
+
53
+ [Quickstart](#-quickstart-in-3-steps) • [Architecture](#-framework-architecture) • [Comparison](#-comparison-with-the-state-of-the-art) • [Theoretical Foundation](#-theoretical-foundations) • [Citation](#-citation)
54
+
55
+ </div>
56
+
57
+ ---
58
+
59
+ ## 🌟 Key Features
60
+
61
+ * 📡 **Automated Scholarly Harvesting:** Direct connection to the **OpenAlex API** (*Polite Pool* with 250M+ works) executing boolean queries and reconstructing inverted-index abstracts in $O(N \log N)$.
62
+ * 🧹 **Bidirectional Deduplication:** Collapses duplicates across arXiv, IEEE, ACM, Springer, and PubMed via canonical lowercase DOI and normalized lexical title hashing.
63
+ * 🧠 **Domain-Specific Transformer Presets:** Plug-and-play dense representations via `Sentence-Transformers`:
64
+ * `software_engineering`: `sentence-transformers/all-MiniLM-L6-v2`
65
+ * `biomedical_health`: `microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract`
66
+ * `scientific_general`: `allenai/scibert_scivocab_uncased`
67
+ * `finance_business`: `ProsusAI/finbert`
68
+ * `multilingual`: `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2`
69
+ * 🔬 **Unsupervised Topic Discovery ($c$-TF-IDF):** Discovers latent research themes without generative hallucination, extracting mathematically distinctive n-grams using *Class-based TF-IDF*.
70
+ * 🗺️ **Interactive Cartography & Cluster Hulls:** Produces publication-grade 2D HTML dashboards (Plotly) featuring:
71
+ * Regional boundaries via **Convex Hulls** with smoothed spline contours.
72
+ * Cluster centroids with real-time metadata cards ($N$, percentage, top keywords).
73
+ * Layer switching (*Full View*, *Cluster Boundaries Only*, *Paper Scatter Points*).
74
+ * 📈 **Temporal Dynamics & Hot Topic Radar:** Computes Compound Annual Growth Rates (CAGR) per cluster to classify topics into 🚀 *Emerging*, ⚖️ *Mature*, or 📉 *Declining*.
75
+ * 🛡️ **Mathematical PRISMA 2020 Audit:** Objective isolation of out-of-scope or foreign language clusters as documented exclusion criteria.
76
+ * 📝 **Automated Manuscript Generation:** Compiles an executive Microsoft Word (`.docx`) template complete with cover page, research questions (RQs), PRISMA summary tables, taxonomy distribution, and structured discussion sections.
77
+
78
+ ---
79
+
80
+ ## 🏗️ Framework Architecture
81
+
82
+ ```mermaid
83
+ graph TD
84
+ A["⚙️ 1. Project Configuration<br><code>scimapper_config.json</code>"] --> B["📡 2. Harvester & Deduplicator<br><code>collector.py (OpenAlex API)</code>"]
85
+ B --> C["🧠 3. Semantic Embeddings<br><code>embedder.py (SBERT / MiniLM)</code>"]
86
+ C --> D["🔬 4. Clustering & c-TF-IDF<br><code>clusterer.py (PCA + t-SNE)</code>"]
87
+ D --> E1["🗺️ 5a. Interactive Cartography<br><code>visualizer.py (Plotly 2D + Hulls)</code>"]
88
+ D --> E2["⚖️ 5b. Human-in-the-Loop Review<br><code>discovered_topics.json</code>"]
89
+ E2 --> F["📝 6. Automated Manuscript<br><code>doc_builder.py (.docx Output)</code>"]
90
+ ```
91
+
92
+ ---
93
+
94
+ ## ⚡ Quickstart in 3 Steps
95
+
96
+ ### 1. Installation
97
+
98
+ Clone the repository and install the dependencies:
99
+
100
+ ```bash
101
+ git clone https://github.com/gustavoandresfu/SciMapper.git
102
+ cd SciMapper
103
+ pip install -r requirements.txt
104
+ ```
105
+
106
+ *(Optional)* Install as an editable command-line utility:
107
+ ```bash
108
+ pip install -e .
109
+ ```
110
+
111
+ ---
112
+
113
+ ### 2. Initialize a Project
114
+
115
+ Launch the interactive configuration wizard (prompts for domain preset, search queries, and project metadata):
116
+
117
+ ```bash
118
+ python main.py --init
119
+ # Or if installed via pip:
120
+ scimapper --init
121
+ ```
122
+ *(Or use `python main.py --init --quick` to generate the baseline template directly without prompts).*
123
+
124
+ The generated `sms_config.json` is ready to inspect and refine:
125
+
126
+ ```json
127
+ {
128
+ "project_metadata": {
129
+ "title": "Systematic Literature Review: Generative AI in Healthcare",
130
+ "short_name": "SciMapper_GenAI_Health",
131
+ "authors": ["Your Name"],
132
+ "temporal_window": [2019, 2026],
133
+ "output_dir": "./output"
134
+ },
135
+ "research_questions": {
136
+ "RQ1": "What foundational architectures and LLMs are predominantly adopted in clinical workflows?",
137
+ "RQ2": "What empirical metrics and validation benchmarks are reported for diagnostic accuracy?",
138
+ "RQ3": "What open challenges regarding hallucinations and ethical safety remain unaddressed?"
139
+ },
140
+ "search_strategy": {
141
+ "openalex_email": "researcher@university.edu",
142
+ "max_results_per_query": 100,
143
+ "queries": [
144
+ "\"generative ai\" AND \"clinical diagnostics\"",
145
+ "\"large language models\" AND \"medical decision support\""
146
+ ]
147
+ },
148
+ "nlp_tuning": {
149
+ "domain_preset": "biomedical_health",
150
+ "n_clusters": 5
151
+ }
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ### 3. Run the Automated Pipeline
158
+
159
+ Execute the discovery phase:
160
+
161
+ ```bash
162
+ python main.py --run-discovery --config sms_config.json
163
+ ```
164
+
165
+ 1. Review and refine taxonomic names in `output/discovered_topics.json`.
166
+ 2. Inspect the pre-selected seminal papers in `output/candidatos_discusion.csv`.
167
+ 3. Compile the interactive dashboard and Word document:
168
+
169
+ ```bash
170
+ python main.py --compile --config sms_config.json
171
+ python main.py --build-doc --config sms_config.json
172
+ ```
173
+
174
+ Or execute everything end-to-end in a single run:
175
+
176
+ ```bash
177
+ python main.py --all --config sms_config.json
178
+ ```
179
+
180
+ ---
181
+
182
+ ## 📊 Comparison with the State-of-the-Art
183
+
184
+ | Capability | ASReview | Generic BERTopic | Manual Review Tools (Covidence / Rayyan) | **SciMapper** |
185
+ | :--- | :---: | :---: | :---: | :---: |
186
+ | **Academic Ingestion** | ❌ Manual (CSV/RIS) | ❌ None | ❌ Manual Import | **✅ Automated OpenAlex API** |
187
+ | **Deduplication** | ⚠️ Basic | ❌ None | ⚠️ Exact match | **✅ Canonical DOI + Title Hash** |
188
+ | **Semantic Representations** | ✅ Optional | ✅ Native | ❌ None | **✅ Pre-tuned Domain Transformers** |
189
+ | **Topic Modeling ($c$-TF-IDF)** | ❌ Binary only | ✅ Yes | ❌ None | **✅ Mathematical $c$-TF-IDF** |
190
+ | **Objective PRISMA Exclusion** | ❌ Human judgment | ❌ None | ❌ Human labeling | **✅ Algorithmic Outlier Clustering** |
191
+ | **Cartography with Convex Hulls** | ❌ None | ⚠️ Scatter only | ❌ None | **✅ 2D Hulls + Centroids + Density** |
192
+ | **Temporal CAGR Tracking** | ❌ None | ❌ Manual | ❌ None | **✅ Automated Hot-Topic Radar** |
193
+ | **Automated Manuscript (.docx)** | ❌ None | ❌ None | ❌ Export tables | **✅ Formatted PRISMA Word Paper** |
194
+
195
+ ---
196
+
197
+ ## 🔬 Theoretical Foundations
198
+
199
+ The framework's methodological and algorithmic foundations are grounded in established literature:
200
+
201
+ 1. **Topic Modeling & Semantic Representation:**
202
+ Based on the modular architecture described by **Jay Alammar and Maarten Grootendorst** in *Hands-On Large Language Models* (O'Reilly, Chapter 5: *Text Clustering and Topic Modeling*), decoupling dense vector embeddings, dimensionality reduction, clustering, and class-based TF-IDF ($c$-TF-IDF).
203
+ 2. **Systematic Mapping Methodology:**
204
+ Follows the seminal guidelines of **Petersen et al. (2008)** (*Systematic Mapping Studies in Software Engineering*) and **Kitchenham & Charters (2007)**.
205
+ 3. **Auditability & Reporting Standards:**
206
+ Strict adherence to the **PRISMA 2020** statement (*Preferred Reporting Items for Systematic Reviews and Meta-Analyses*), ensuring transparent and reproducible record accounting.
207
+
208
+ ---
209
+
210
+ ## 📁 Repository Structure
211
+
212
+ ```text
213
+ SciMapper/
214
+ ├── config_template.json # Master template for project setup
215
+ ├── test_config.json # Quick verification test suite
216
+ ├── main.py # Unified CLI orchestrator
217
+ ├── requirements.txt # Python dependency specification
218
+ ├── pyproject.toml # Standard packaging & CLI entry point (scimapper)
219
+ ├── CITATION.cff # Academic citation metadata
220
+ ├── LICENSE # MIT Open Source License
221
+ └── core/
222
+ ├── collector.py # OpenAlex API ingestion & abstract reconstruction
223
+ ├── embedder.py # Multi-domain Sentence-Transformer pipeline
224
+ ├── clusterer.py # Dimensionality reduction (PCA+t-SNE) & c-TF-IDF
225
+ ├── selector.py # Stratified seminal paper recommendation
226
+ ├── visualizer.py # Plotly 2D interactive maps with Convex Hulls
227
+ └── doc_builder.py # Automated PRISMA Word manuscript generation
228
+ ```
229
+
230
+ ---
231
+
232
+ ## 📖 Citation
233
+
234
+ If you use **SciMapper** in your research, academic reviews, or dissertations, please cite it as:
235
+
236
+ ```bibtex
237
+ @software{futo_scimapper_2026,
238
+ author = {Gustavo Andrés Futo},
239
+ title = {SciMapper: Automated Scientific Mapping & Systematic Literature Reviews with Dense Semantic Clustering and PRISMA 2020 Compliance},
240
+ year = {2026},
241
+ publisher = {GitHub},
242
+ journal = {GitHub repository},
243
+ howpublished = {\url{https://github.com/gustavoandresfu/SciMapper}}
244
+ }
245
+ ```
246
+
247
+ ---
248
+
249
+ ## 📄 License
250
+
251
+ This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for details.
252
+ Author: **Gustavo Andrés Futo** (2026).
@@ -0,0 +1,216 @@
1
+ <div align="center">
2
+
3
+ # 🚀 SciMapper
4
+ ### Automated Scientific Mapping & Systematic Literature Reviews with Dense Semantic Clustering
5
+
6
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg?logo=python&logoColor=white)](https://www.python.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![PRISMA 2020](https://img.shields.io/badge/PRISMA-2020%20Compliant-green.svg)](https://www.prisma-statement.org/)
9
+ [![OpenAlex API](https://img.shields.io/badge/Data%20Source-OpenAlex%20API-orange.svg)](https://openalex.org/)
10
+ [![NLP Engine](https://img.shields.io/badge/NLP-Sentence--Transformers-purple.svg)](https://www.sbert.net/)
11
+
12
+ **An end-to-end, domain-agnostic framework designed to conduct reproducible Systematic Literature Reviews (SLR) and Systematic Mapping Studies (SMS).**
13
+ It automates academic corpus harvesting, deduplication, dense semantic embedding, unsupervised clustering, taxonomic discovery, interactive 2D cartography, and manuscript drafting—while keeping **researchers firmly in the loop**.
14
+
15
+ 🌐 **Languages:** **English** • [Español (Guía en Castellano)](README_ES.md)
16
+
17
+ [Quickstart](#-quickstart-in-3-steps) • [Architecture](#-framework-architecture) • [Comparison](#-comparison-with-the-state-of-the-art) • [Theoretical Foundation](#-theoretical-foundations) • [Citation](#-citation)
18
+
19
+ </div>
20
+
21
+ ---
22
+
23
+ ## 🌟 Key Features
24
+
25
+ * 📡 **Automated Scholarly Harvesting:** Direct connection to the **OpenAlex API** (*Polite Pool* with 250M+ works) executing boolean queries and reconstructing inverted-index abstracts in $O(N \log N)$.
26
+ * 🧹 **Bidirectional Deduplication:** Collapses duplicates across arXiv, IEEE, ACM, Springer, and PubMed via canonical lowercase DOI and normalized lexical title hashing.
27
+ * 🧠 **Domain-Specific Transformer Presets:** Plug-and-play dense representations via `Sentence-Transformers`:
28
+ * `software_engineering`: `sentence-transformers/all-MiniLM-L6-v2`
29
+ * `biomedical_health`: `microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract`
30
+ * `scientific_general`: `allenai/scibert_scivocab_uncased`
31
+ * `finance_business`: `ProsusAI/finbert`
32
+ * `multilingual`: `sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2`
33
+ * 🔬 **Unsupervised Topic Discovery ($c$-TF-IDF):** Discovers latent research themes without generative hallucination, extracting mathematically distinctive n-grams using *Class-based TF-IDF*.
34
+ * 🗺️ **Interactive Cartography & Cluster Hulls:** Produces publication-grade 2D HTML dashboards (Plotly) featuring:
35
+ * Regional boundaries via **Convex Hulls** with smoothed spline contours.
36
+ * Cluster centroids with real-time metadata cards ($N$, percentage, top keywords).
37
+ * Layer switching (*Full View*, *Cluster Boundaries Only*, *Paper Scatter Points*).
38
+ * 📈 **Temporal Dynamics & Hot Topic Radar:** Computes Compound Annual Growth Rates (CAGR) per cluster to classify topics into 🚀 *Emerging*, ⚖️ *Mature*, or 📉 *Declining*.
39
+ * 🛡️ **Mathematical PRISMA 2020 Audit:** Objective isolation of out-of-scope or foreign language clusters as documented exclusion criteria.
40
+ * 📝 **Automated Manuscript Generation:** Compiles an executive Microsoft Word (`.docx`) template complete with cover page, research questions (RQs), PRISMA summary tables, taxonomy distribution, and structured discussion sections.
41
+
42
+ ---
43
+
44
+ ## 🏗️ Framework Architecture
45
+
46
+ ```mermaid
47
+ graph TD
48
+ A["⚙️ 1. Project Configuration<br><code>scimapper_config.json</code>"] --> B["📡 2. Harvester & Deduplicator<br><code>collector.py (OpenAlex API)</code>"]
49
+ B --> C["🧠 3. Semantic Embeddings<br><code>embedder.py (SBERT / MiniLM)</code>"]
50
+ C --> D["🔬 4. Clustering & c-TF-IDF<br><code>clusterer.py (PCA + t-SNE)</code>"]
51
+ D --> E1["🗺️ 5a. Interactive Cartography<br><code>visualizer.py (Plotly 2D + Hulls)</code>"]
52
+ D --> E2["⚖️ 5b. Human-in-the-Loop Review<br><code>discovered_topics.json</code>"]
53
+ E2 --> F["📝 6. Automated Manuscript<br><code>doc_builder.py (.docx Output)</code>"]
54
+ ```
55
+
56
+ ---
57
+
58
+ ## ⚡ Quickstart in 3 Steps
59
+
60
+ ### 1. Installation
61
+
62
+ Clone the repository and install the dependencies:
63
+
64
+ ```bash
65
+ git clone https://github.com/gustavoandresfu/SciMapper.git
66
+ cd SciMapper
67
+ pip install -r requirements.txt
68
+ ```
69
+
70
+ *(Optional)* Install as an editable command-line utility:
71
+ ```bash
72
+ pip install -e .
73
+ ```
74
+
75
+ ---
76
+
77
+ ### 2. Initialize a Project
78
+
79
+ Launch the interactive configuration wizard (prompts for domain preset, search queries, and project metadata):
80
+
81
+ ```bash
82
+ python main.py --init
83
+ # Or if installed via pip:
84
+ scimapper --init
85
+ ```
86
+ *(Or use `python main.py --init --quick` to generate the baseline template directly without prompts).*
87
+
88
+ The generated `sms_config.json` is ready to inspect and refine:
89
+
90
+ ```json
91
+ {
92
+ "project_metadata": {
93
+ "title": "Systematic Literature Review: Generative AI in Healthcare",
94
+ "short_name": "SciMapper_GenAI_Health",
95
+ "authors": ["Your Name"],
96
+ "temporal_window": [2019, 2026],
97
+ "output_dir": "./output"
98
+ },
99
+ "research_questions": {
100
+ "RQ1": "What foundational architectures and LLMs are predominantly adopted in clinical workflows?",
101
+ "RQ2": "What empirical metrics and validation benchmarks are reported for diagnostic accuracy?",
102
+ "RQ3": "What open challenges regarding hallucinations and ethical safety remain unaddressed?"
103
+ },
104
+ "search_strategy": {
105
+ "openalex_email": "researcher@university.edu",
106
+ "max_results_per_query": 100,
107
+ "queries": [
108
+ "\"generative ai\" AND \"clinical diagnostics\"",
109
+ "\"large language models\" AND \"medical decision support\""
110
+ ]
111
+ },
112
+ "nlp_tuning": {
113
+ "domain_preset": "biomedical_health",
114
+ "n_clusters": 5
115
+ }
116
+ }
117
+ ```
118
+
119
+ ---
120
+
121
+ ### 3. Run the Automated Pipeline
122
+
123
+ Execute the discovery phase:
124
+
125
+ ```bash
126
+ python main.py --run-discovery --config sms_config.json
127
+ ```
128
+
129
+ 1. Review and refine taxonomic names in `output/discovered_topics.json`.
130
+ 2. Inspect the pre-selected seminal papers in `output/candidatos_discusion.csv`.
131
+ 3. Compile the interactive dashboard and Word document:
132
+
133
+ ```bash
134
+ python main.py --compile --config sms_config.json
135
+ python main.py --build-doc --config sms_config.json
136
+ ```
137
+
138
+ Or execute everything end-to-end in a single run:
139
+
140
+ ```bash
141
+ python main.py --all --config sms_config.json
142
+ ```
143
+
144
+ ---
145
+
146
+ ## 📊 Comparison with the State-of-the-Art
147
+
148
+ | Capability | ASReview | Generic BERTopic | Manual Review Tools (Covidence / Rayyan) | **SciMapper** |
149
+ | :--- | :---: | :---: | :---: | :---: |
150
+ | **Academic Ingestion** | ❌ Manual (CSV/RIS) | ❌ None | ❌ Manual Import | **✅ Automated OpenAlex API** |
151
+ | **Deduplication** | ⚠️ Basic | ❌ None | ⚠️ Exact match | **✅ Canonical DOI + Title Hash** |
152
+ | **Semantic Representations** | ✅ Optional | ✅ Native | ❌ None | **✅ Pre-tuned Domain Transformers** |
153
+ | **Topic Modeling ($c$-TF-IDF)** | ❌ Binary only | ✅ Yes | ❌ None | **✅ Mathematical $c$-TF-IDF** |
154
+ | **Objective PRISMA Exclusion** | ❌ Human judgment | ❌ None | ❌ Human labeling | **✅ Algorithmic Outlier Clustering** |
155
+ | **Cartography with Convex Hulls** | ❌ None | ⚠️ Scatter only | ❌ None | **✅ 2D Hulls + Centroids + Density** |
156
+ | **Temporal CAGR Tracking** | ❌ None | ❌ Manual | ❌ None | **✅ Automated Hot-Topic Radar** |
157
+ | **Automated Manuscript (.docx)** | ❌ None | ❌ None | ❌ Export tables | **✅ Formatted PRISMA Word Paper** |
158
+
159
+ ---
160
+
161
+ ## 🔬 Theoretical Foundations
162
+
163
+ The framework's methodological and algorithmic foundations are grounded in established literature:
164
+
165
+ 1. **Topic Modeling & Semantic Representation:**
166
+ Based on the modular architecture described by **Jay Alammar and Maarten Grootendorst** in *Hands-On Large Language Models* (O'Reilly, Chapter 5: *Text Clustering and Topic Modeling*), decoupling dense vector embeddings, dimensionality reduction, clustering, and class-based TF-IDF ($c$-TF-IDF).
167
+ 2. **Systematic Mapping Methodology:**
168
+ Follows the seminal guidelines of **Petersen et al. (2008)** (*Systematic Mapping Studies in Software Engineering*) and **Kitchenham & Charters (2007)**.
169
+ 3. **Auditability & Reporting Standards:**
170
+ Strict adherence to the **PRISMA 2020** statement (*Preferred Reporting Items for Systematic Reviews and Meta-Analyses*), ensuring transparent and reproducible record accounting.
171
+
172
+ ---
173
+
174
+ ## 📁 Repository Structure
175
+
176
+ ```text
177
+ SciMapper/
178
+ ├── config_template.json # Master template for project setup
179
+ ├── test_config.json # Quick verification test suite
180
+ ├── main.py # Unified CLI orchestrator
181
+ ├── requirements.txt # Python dependency specification
182
+ ├── pyproject.toml # Standard packaging & CLI entry point (scimapper)
183
+ ├── CITATION.cff # Academic citation metadata
184
+ ├── LICENSE # MIT Open Source License
185
+ └── core/
186
+ ├── collector.py # OpenAlex API ingestion & abstract reconstruction
187
+ ├── embedder.py # Multi-domain Sentence-Transformer pipeline
188
+ ├── clusterer.py # Dimensionality reduction (PCA+t-SNE) & c-TF-IDF
189
+ ├── selector.py # Stratified seminal paper recommendation
190
+ ├── visualizer.py # Plotly 2D interactive maps with Convex Hulls
191
+ └── doc_builder.py # Automated PRISMA Word manuscript generation
192
+ ```
193
+
194
+ ---
195
+
196
+ ## 📖 Citation
197
+
198
+ If you use **SciMapper** in your research, academic reviews, or dissertations, please cite it as:
199
+
200
+ ```bibtex
201
+ @software{futo_scimapper_2026,
202
+ author = {Gustavo Andrés Futo},
203
+ title = {SciMapper: Automated Scientific Mapping & Systematic Literature Reviews with Dense Semantic Clustering and PRISMA 2020 Compliance},
204
+ year = {2026},
205
+ publisher = {GitHub},
206
+ journal = {GitHub repository},
207
+ howpublished = {\url{https://github.com/gustavoandresfu/SciMapper}}
208
+ }
209
+ ```
210
+
211
+ ---
212
+
213
+ ## 📄 License
214
+
215
+ This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for details.
216
+ Author: **Gustavo Andrés Futo** (2026).
@@ -0,0 +1,11 @@
1
+ """Core modules for SciMapper."""
2
+
3
+ import sys
4
+
5
+ try:
6
+ if hasattr(sys.stdout, "reconfigure"):
7
+ sys.stdout.reconfigure(encoding="utf-8")
8
+ if hasattr(sys.stderr, "reconfigure"):
9
+ sys.stderr.reconfigure(encoding="utf-8")
10
+ except Exception:
11
+ pass
@@ -0,0 +1,178 @@
1
+ """
2
+ AutoSMS Framework - Módulo de Clustering, c-TF-IDF y Dinámica Temporal
3
+ =====================================================================
4
+ Ejecuta la reducción bidimensional (PCA + t-SNE), agrupamiento semántico,
5
+ extracción formal de palabras clave diferenciales (c-TF-IDF) y el cálculo
6
+ del Radar de Madurez Temporal (CAGR y clasificación de tendencias).
7
+ """
8
+
9
+ import os
10
+ import json
11
+ import logging
12
+ import numpy as np
13
+ import pandas as pd
14
+ from sklearn.decomposition import PCA
15
+ from sklearn.manifold import TSNE
16
+ from sklearn.cluster import KMeans
17
+ from sklearn.feature_extraction.text import CountVectorizer
18
+
19
+ logger = logging.getLogger("scimapper.clusterer")
20
+
21
+ class AutoClusterer:
22
+ def __init__(self, config: dict):
23
+ self.config = config
24
+ self.nlp_cfg = config.get("nlp_tuning", {})
25
+ self.output_dir = config.get("project_metadata", {}).get("output_dir", "./output")
26
+ os.makedirs(self.output_dir, exist_ok=True)
27
+ self.k = self.nlp_cfg.get("n_clusters", 6)
28
+
29
+ def reduce_2d(self, embeddings: np.ndarray) -> np.ndarray:
30
+ logger.info("Reduciendo dimensionalidad a espacio bidimensional (PCA + t-SNE)...")
31
+ n_samples = embeddings.shape[0]
32
+ if n_samples <= 2:
33
+ return np.zeros((n_samples, 2))
34
+
35
+ pca_dims = min(50, embeddings.shape[1], n_samples - 1)
36
+ pca = PCA(n_components=pca_dims, random_state=42)
37
+ pca_feats = pca.fit_transform(embeddings)
38
+
39
+ perp = min(30, max(2, (n_samples - 1) // 3))
40
+ tsne = TSNE(n_components=2, perplexity=perp, learning_rate="auto", init="pca", random_state=42)
41
+ coords = tsne.fit_transform(pca_feats)
42
+ return coords
43
+
44
+ def cluster(self, embeddings: np.ndarray) -> np.ndarray:
45
+ n_samples = embeddings.shape[0]
46
+ actual_k = min(self.k, max(1, n_samples // 2))
47
+ logger.info("Ejecutando agrupamiento no supervisado en k=%d clusters...", actual_k)
48
+ if actual_k <= 1:
49
+ return np.zeros(n_samples, dtype=int)
50
+ kmeans = KMeans(n_clusters=actual_k, random_state=42, n_init=10)
51
+ labels = kmeans.fit_predict(embeddings)
52
+ return labels
53
+
54
+ def extract_c_tf_idf(self, texts: list, labels: np.ndarray, top_n: int = 8) -> dict:
55
+ logger.info("Calculando Class-based TF-IDF (c-TF-IDF) para extraccion lexica...")
56
+ unique_labels = sorted(list(set(labels)))
57
+ docs_per_cluster = []
58
+ for l in unique_labels:
59
+ cluster_docs = [texts[i] for i in range(len(texts)) if labels[i] == l]
60
+ docs_per_cluster.append(" ".join(cluster_docs))
61
+
62
+ stop_words = self.nlp_cfg.get("stop_words", "english")
63
+ if isinstance(stop_words, str) and stop_words.lower() in ("none", "null", ""):
64
+ stop_words = None
65
+
66
+ vec = CountVectorizer(ngram_range=(1, 2), stop_words=stop_words, min_df=1, max_df=1.0)
67
+ X = vec.fit_transform(docs_per_cluster)
68
+ words = vec.get_feature_names_out()
69
+
70
+ tf = X.toarray().astype(float)
71
+ w_sum = tf.sum(axis=1, keepdims=True)
72
+ tf_norm = tf / np.maximum(w_sum, 1)
73
+
74
+ # IDF clásico por documento (cluster): log(1 + N / (df + 1))
75
+ doc_freq = (tf > 0).sum(axis=0).astype(float)
76
+ n_clusters = max(1, len(docs_per_cluster))
77
+ idf = np.log(1.0 + (n_clusters / (doc_freq + 1.0)))
78
+ c_tf_idf = tf_norm * idf
79
+
80
+ keywords_dict = {}
81
+ for idx, l in enumerate(unique_labels):
82
+ top_idx = np.argsort(c_tf_idf[idx])[::-1][:top_n]
83
+ top_words = [words[i] for i in top_idx if len(words[i]) > 2]
84
+ keywords_dict[int(l)] = top_words
85
+
86
+ return keywords_dict
87
+
88
+ def compute_temporal_dynamics(self, df: pd.DataFrame, labels: np.ndarray) -> dict:
89
+ logger.info("Calculando Radar de Madurez Temporal y CAGR por Topico...")
90
+ dynamics = {}
91
+ unique_labels = sorted(list(set(labels)))
92
+
93
+ # Convertir años a enteros válidos
94
+ years_series = pd.to_numeric(df["publication_year"], errors="coerce").dropna()
95
+ if years_series.empty:
96
+ min_year, max_year = 2018, 2026
97
+ else:
98
+ min_year, max_year = int(years_series.min()), int(years_series.max())
99
+
100
+ span = max(1, max_year - min_year)
101
+
102
+ for l in unique_labels:
103
+ sub = df[df["topic_id"] == l]
104
+ sub_years = pd.to_numeric(sub["publication_year"], errors="coerce").dropna().astype(int)
105
+
106
+ yearly_counts = {}
107
+ for y in range(min_year, max_year + 1):
108
+ yearly_counts[y] = int((sub_years == y).sum())
109
+
110
+ # Cálculo de CAGR suavizado (Laplace +1 para evitar ceros)
111
+ start_val = yearly_counts.get(min_year, 0) + yearly_counts.get(min_year + 1, 0)
112
+ end_val = yearly_counts.get(max_year, 0) + yearly_counts.get(max_year - 1, 0)
113
+
114
+ cagr = ((end_val + 1.0) / (start_val + 1.0)) ** (1.0 / max(1, span - 1)) - 1.0
115
+ cagr_pct = round(cagr * 100, 1)
116
+
117
+ # Proporción de producción en los últimos 3 años
118
+ recent_years = [max_year, max_year - 1, max_year - 2]
119
+ recent_count = sum(yearly_counts.get(y, 0) for y in recent_years)
120
+ recent_ratio = round((recent_count / max(1, len(sub))) * 100, 1)
121
+
122
+ # Clasificación de la dinámica
123
+ if cagr_pct >= 12.0 or recent_ratio >= 45.0:
124
+ category = "Emergente (Hot Topic)"
125
+ badge = "🚀 Emergente"
126
+ elif cagr_pct <= -8.0 and recent_ratio <= 22.0:
127
+ category = "En Declive"
128
+ badge = "📉 En Declive"
129
+ else:
130
+ category = "Maduro / Consolidado"
131
+ badge = "⚖️ Maduro"
132
+
133
+ dynamics[int(l)] = {
134
+ "cagr_percent": cagr_pct,
135
+ "recent_ratio_percent": recent_ratio,
136
+ "trend_category": category,
137
+ "badge": badge,
138
+ "yearly_distribution": yearly_counts
139
+ }
140
+
141
+ return dynamics
142
+
143
+ def run(self, df: pd.DataFrame, embeddings: np.ndarray) -> tuple:
144
+ df = df.reset_index(drop=True).copy()
145
+ coords = self.reduce_2d(embeddings)
146
+ df["coord_x"] = coords[:, 0]
147
+ df["coord_y"] = coords[:, 1]
148
+
149
+ labels = self.cluster(embeddings)
150
+ df["topic_id"] = labels
151
+
152
+ texts = (df["title"] + ". " + df["abstract"]).tolist()
153
+ keywords = self.extract_c_tf_idf(texts, labels, top_n=8)
154
+ temporal_info = self.compute_temporal_dynamics(df, labels)
155
+
156
+ # Generar JSON de tópicos descubiertos enriquecido
157
+ topics_summary = {}
158
+ for l in sorted(keywords.keys()):
159
+ sub = df[df["topic_id"] == l]
160
+ sample_titles = sub["title"].head(4).tolist()
161
+ t_dyn = temporal_info.get(l, {})
162
+
163
+ topics_summary[l] = {
164
+ "count": len(sub),
165
+ "percentage": round(len(sub) / len(df) * 100, 1),
166
+ "keywords": keywords[l],
167
+ "sample_titles": sample_titles,
168
+ "assigned_name": f"Tópico {l}: {', '.join(keywords[l][:3]).title()}",
169
+ "exclude_prisma": False,
170
+ "temporal_dynamics": t_dyn
171
+ }
172
+
173
+ topics_json_path = os.path.join(self.output_dir, "discovered_topics.json")
174
+ with open(topics_json_path, "w", encoding="utf-8") as f:
175
+ json.dump(topics_summary, f, indent=2, ensure_ascii=False)
176
+
177
+ logger.info("Archivo de ajuste humano generado en: %s", topics_json_path)
178
+ return df, topics_summary