# How to Use LangExtract's Visualization for Extracted Entities: A Complete Guide

> Learn to use LangExtract's visualization tool to highlight extracted entities in text with interactive HTML pages color-coded spans and playback controls. A complete guide for google/langextract.

- Repository: [Google/langextract](https://github.com/google/langextract)
- Tags: how-to-guide
- Published: 2026-02-16

---

**LangExtract's visualization tool converts `AnnotatedDocument` objects into interactive HTML pages that highlight extracted entities directly in the original text with color-coded spans and playback controls.**

LangExtract ships with a self-contained visualization module that transforms extraction results into browsable, interactive documents. Whether you are working inside a Jupyter notebook or generating standalone HTML reports, the `visualize()` function in [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py) handles everything from color assignment to JavaScript generation.

## How LangExtract's Visualization Works

The visualization pipeline operates in three distinct stages that you can trace through the source code.

### Stage 1: Loading and Validating Documents

The `visualize()` function accepts three input types: an `AnnotatedDocument` object, a path to a JSONL file, or a string path. When a file path is provided, the function calls `langextract.io.load_annotated_documents_jsonl` to read the first document. It then validates that the required `text` and `extractions` fields are present.

This logic resides at the start of the `visualize()` function in [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py) (lines 54-61).

### Stage 2: Preparing Extraction Data

Before rendering, the system filters and enriches the extraction data:

- **`_filter_valid_extractions()`** removes any extraction lacking a proper `char_interval` (lines 96-108)
- **`_assign_colors()`** builds a deterministic color map that assigns each unique extraction class to a hex color from a built-in palette (lines 79-93)
- **`_prepare_extraction_data()`** creates a JSON-serializable list containing attributes, context snippets, colors, and start/end positions for the JavaScript renderer

### Stage 3: Rendering Interactive HTML

The `_build_visualization_html()` function (lines 174-224) assembles the final output by combining:

- **CSS styling** from `_VISUALIZATION_CSS` that defines `.lx-highlight` classes, tooltips, controls, and legend positioning
- **Highlighted text** generated by `_build_highlighted_text()`, which inserts `<span>` tags while respecting proper nesting using `SpanPoint` and `TagType` logic
- **Interactive controls** including a legend showing the color-to-class mapping and JavaScript widgets for play/pause, stepping forward/backward, and slider-based navigation

When running inside a Jupyter environment (detected by `_is_jupyter()`), the function returns an `IPython.display.HTML` object; otherwise, it returns a plain HTML string.

## Visualizing Extractions in Jupyter Notebooks

To see LangExtract's visualization in action immediately after extraction:

```python
import langextract as lx

# Run extraction with any provider (Gemini, Ollama, etc.)

doc = lx.extract(
    "Romeo and Juliet meet at the market. Romeo is a lover.",
    schema=[
        {"extraction_class": "PERSON", "prompt": "Extract person names"},
        {"extraction_class": "PLACE", "prompt": "Extract place names"},
    ],
)

# Display interactive visualization

lx.visualize(doc)

```

The output displays the original text with colored spans highlighting each extraction, a legend mapping colors to entity classes, and playback controls that let you step through each extraction sequentially.

## Rendering Visualizations from JSONL Files

For batch processing workflows, you can visualize previously saved results without reloading the extraction pipeline:

```python
import langextract as lx
from pathlib import Path

jsonl_path = Path("my_batch_results.jsonl")
html_output = lx.visualize(
    jsonl_path, 
    animation_speed=0.5, 
    show_legend=False
)

# Save to file for sharing

Path("visualization.html").write_text(html_output)

```

Key parameters for `visualize()` include:

- **`animation_speed`**: Controls the delay in seconds between automatic jumps during playback (default is `1.0`)
- **`show_legend`**: Set to `False` to hide the color-to-class mapping legend
- **`gif_optimized`**: When `True` (default), applies larger fonts and higher contrast suitable for screen recording or GIF creation

## Customizing Colors and Appearance

The visualizer uses a built-in palette defined as `_PALETTE` in [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py). For temporary customization in notebooks, you can monkey-patch the palette before calling `visualize()`:

```python
import langextract as lx
import langextract.visualization as viz

# Replace with custom hex colors

viz._PALETTE = ["#ff6b6b", "#4ecdc4", "#45b7d1", "#96ceb4"]

lx.visualize(doc)

```

**Note**: This approach modifies the module state for the current session only. For permanent changes, edit the `_PALETTE` definition directly in the source file at [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py).

## Summary

- LangExtract's visualization module converts `AnnotatedDocument` objects into interactive HTML using the `visualize()` function in [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py)
- The pipeline validates input, filters extractions with valid `char_interval`s, assigns deterministic colors per extraction class, and renders highlighted spans with JavaScript controls
- Jupyter notebooks receive `IPython.display.HTML` objects for inline rendering, while standalone scripts receive HTML strings suitable for file output
- Control animation speed, legend visibility, and GIF optimization through function parameters
- Customize colors by modifying the `_PALETTE` list in [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py)

## Frequently Asked Questions

### How do I save the LangExtract visualization as an HTML file?

When running outside a Jupyter environment, `lx.visualize()` returns a string containing the complete HTML document. Write this string to a file using standard Python file operations: `Path("output.html").write_text(html_string)`. When running inside Jupyter, the function displays the visualization inline and returns an `IPython.display.HTML` object, which you can convert to string using `str(html_object.data)` if needed.

### Can I visualize multiple documents at once from a JSONL file?

The `visualize()` function processes one document at a time. When you pass a JSONL file path, it automatically loads and visualizes only the first document in the file. To visualize multiple documents, iterate through the file using `langextract.io.load_annotated_documents_jsonl()` and call `visualize()` on each document separately, saving each output to a different HTML file or displaying them sequentially in a notebook.

### Why are some extractions missing from the visualization?

Extractions without a valid `char_interval` attribute are automatically filtered out during the preparation stage by the `_filter_valid_extractions()` function in [`langextract/visualization.py`](https://github.com/google/langextract/blob/main/langextract/visualization.py). This ensures that only extractions with precise character offsets can be highlighted in the text. If your extraction schema produces entities without character positions, or if the extraction provider failed to generate offsets, those entities will not appear in the visual output.

### How can I change the animation speed in the interactive viewer?

Pass the `animation_speed` parameter to `lx.visualize()` with a float value representing the delay in seconds between automatic steps. The default value is `1.0` second. For faster playback, use a smaller value like `0.5` or `0.3`. To disable automatic animation and allow manual stepping only, you would need to modify the generated JavaScript, as the current API does not expose a direct "pause by default" parameter.