This repository contains the following elements:
- Narrative Maps Visualization Tool ("NMVT.py").
- Testing data sets ("data" folder).
- Custom data preparation ("preprocessing" folder, see below for details).
- Tutorial and examples ("tutorial" folder), see the detailed tutorial here.
This is a major release that required updating several parts of the code to handle outdated libraries and dependency issues. Note that older versions of the repository contained some additional experiments and validations. For simplicity in the "release" version, I decided to simplify the structure.
Please cite the following publication if you use this repository:
@article{keith2025nmvt,
title = {Narrative Maps Visualization Tool (NMVT): An interactive narrative analytics system based on the narrative maps framework},
journal = {SoftwareX},
volume = {32},
pages = {102377},
year = {2025},
issn = {2352-7110},
doi = {https://doi.org/10.1016/j.softx.2025.102377},
url = {https://www.sciencedirect.com/science/article/pii/S2352711025003437},
author = {Brian {Keith Norambuena}},
keywords = {Narrative extraction, Visual analytics, Sensemaking, Explainable AI},
}
The following articles are based on our work on this functional prototype:
- Keith and Mitra (2020). This article presents the Narrative Maps framework and the basic extraction algorithm.
- Keith, Mitra, and North (2022). This article presents the design guidelines that we followed in the implementation of our system.
- Keith, Mitra, and North (2023). This article presents the semantic interaction (SI) model of our system, along with evaluations based on simulations and expert feedback.
- Keith (2025). This article presents the interactive narrative analytics system and technical information about its design.
- Keith, German, Krokos, Joseph, and North (2025). This article presents the explainable AI (XAI) components of our work and an associated user study.
- Keith, German, Krokos, Joseph, and North (2026). This article presents an insight-based evaluation of the SI components of our work.
The following are other useful resources and related work in the field of Interactive Narrative Analytics (INA):
- Keith (2026). This article presents the general foundation of the field of INA and its challenges at the time of publication.
- German, Keith, and North (2025). This article presents an alternative extraction algorithm (Narrative Trails) and compares it with a simplified version of Narrative Maps. It also has an associated GitHub repository.
- Keith, Rojas, Meneses, Lam, Flores, Molina, and Leyton (2026). This article presents a modified version of the Narrative Trails method that steers narratives based on human-provided agendas using LLMs, allowing the extraction of customized narratives from document collections without sacrificing coherence.
First, ensure you have Python 3.12 and GraphViz installed on your system.
Set up the environment:
On Linux/Mac:
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txtOn Windows:
python -m venv .venv && .venv\Scripts\activate && pip install -r requirements.txtNote for Windows users: If you encounter issues installing pygraphviz, try:
set INCLUDE=C:\Program Files\Graphviz\include
set LIB=C:\Program Files\Graphviz\lib
pip install pygraphviz --no-binary pygraphvizThen, in the root directory of the project, run:
python NMVT.pyThe easiest way to run the Narrative Maps tool is using Docker, which handles all dependencies automatically. Note that the first build might take a while as it downloads and installs all dependencies.
- Clone this repository
- Navigate to the project directory
- Run the following command:
docker-compose up --build- Open your browser and go to
http://localhost:8050
To run with Custom data in your local version. Simply create a "custom.csv" file, place it in the "data" folder, and select the "Custom" option in the data selection drop down in the main menu.
The CSV file must have the following structure (columns):
- id (numerical id, assumed integer, assumed 0-indexed in increasing order by date, so 0 is the first document in temporal order)
- title (title, used for display in the map)
- url (can be empty, but needs to exist as a column, if it exists a link will be added in the event details tab)
- date (date of the document, can be a regular date or a date time)
- publication (source of the document, in our case it's mostly news outlets either as a string or as a partial URL, but it can be anything in practice, if no specific logo is available for the source a blank marker is used in the map)
- full_text (the full text of the document)
- embedding (we recommend using an embedding with the all-MiniLM-L6-v2 model from SentenceTransformers) - note that we can easily swap the model to a different one, but it requires generating all the pre-computed embeddings again for all data sets.
If you have a data set with the first 6 columns (id, title, url, date, publication, full_text), you can generate the embeddings using the Jupyter notebook "Prepare_Embeddings.ipynb" available in the "preprocessing" folder. The Jupyter notebook has the following requirements:
ftfy==6.0.3
numpy==1.21.2
pandas==1.2.4
sentence_transformers==2.2.2
Please note that the data set must be sorted in ascending order by time and the id column must also align with that, as the system makes assumptions on the temporal order of the documents based on their listing order in the data set.
- The seed is fixed for reproducibility, but the results will likely be different in each system (although consistent within it). I'm not sure if this can be fixed so that the same results can be obtained in all systems.
- Sometimes the same result may look different due to the layout engine producing different results (probably due to random initliazation, not sure if that can be fixed, but it is not a major issue usually).
- The first execution of the narrative extraction method is probably going to be slow.
- The first time you run a specific data set requires extra computation as it needs to precompute some similarity tables and entity information that is then saved for later runs.
- After that, the performance should stabilize.
- Narrative maps are visualized using dash-cytoscape.
- Optimization is done via linear programming using PuLP.
- The connection explanation and event comparison functions use SHAP to generate explanations. This approach was adapted from this implementation of text similarity explainable metrics.
Here is the list of requirements for the project.
System Requirements:
- Python 3.12
- GraphViz (required for
pygraphviz)
Python Packages:
All required packages are listed in requirements.txt:
dash==3.0.4
dash_bootstrap_components==2.0.2
dash_cytoscape==1.0.1
dash_daq==0.6.0
dash_extensions==2.0.4
Flask==3.0.3
ftfy==6.0.3
hdbscan==0.8.39
matplotlib==3.10.3
networkx==3.4.2
nltk==3.8.1
numpy==2.2.5
pandas==2.2.3
plotly==6.1.0
PuLP==2.5.0
python_dateutil==2.8.2
scikit_learn==1.6.0
scipy==1.15.3
sentence_transformers==4.1.0
shap==0.47.2
spacy==3.8.4
transformers==4.51.3
truecase==0.0.14
umap_learn==0.5.8
torch==2.7.0
pygraphviz==1.14
en-core-web-md @ https://github.com/explosion/spacy-models/releases/download/en_core_web_md-3.8.0/en_core_web_md-3.8.0-py3-none-any.whl
Additional Setup:
On the first run, the system will automatically download required NLTK data (stopwords, punkt, and wordnet).
- Complex Maps: When the maps become too big or too complex to handle by the layout engine, there will be issues with the bounding boxes of the storyline (e.g., a big gray box that engulfs everything else). This seems to be an issue with the GraphViz/DOT engine that's running behind the scenes. It doesn't look like a limitation of Cytoscape. But I might be wrong.
- Cluster Coloring: In some rare cases (I haven't been able to reproduce this yet), nodes that have been assigned to a specific cluster (e.g. "blue") get their color removed in the next iteration, despite still belonging to that cluster and still being used by the semantic interaction code as such. This is only a display issue, but it might be annoying.
Please let me know if you find anything else.