WizMap

repository·main·Indexed 19 days ago

https://github.com/poloclub/wizmap

A scalable interactive visualization tool for exploring and interpreting large machine learning embeddings (up to millions of points) in a web browser. It utilizes a multi-resolution summarization method, featuring WebGL rendering for scatter plots and SVG rendering for KDE contours and topic labels. The library provides utilities for generating required density grid JSON and NDJSON data files, as well as a JsonPointContentConfig class for mapping custom metadata to visual elements.

Tokens
7.7K
Snippets
37
Records
41
Agent score
65%

What's inside wizmap

  1. Share a WizMap via URL

    main

    You can share specific embedding maps with collaborators by constructing a URL that includes the dataURL and gridURL query parameters. These parameters point to the JSON files containing your embedding data and grid information.

    Example URL structure: https://poloclub.github.io/wizmap/?dataURL=<URL_TO_DATA_NDJSON>&gridURL=<URL_TO_GRID_JSON>

  2. Use your own embeddings with the WizMap Python library

    main

    To visualize your own machine learning embeddings, use the wizmap Python library to generate the necessary JSON files (containing embedding summaries, distributions, and original data) and then visualize them.

    1. Install the library

    pip install wizmap

    2. Generate and Visualize

    Detailed guides for text and image datasets are available in the following notebooks:

    Once you have generated the required JSON files, you can visualize them in two ways:

    Option A: Browser

    1. Open the WizMap demo.
    2. Click the folder icon on the bottom right.
    3. Enter the URLs to your generated JSON files in the pop-up window.

    Option B: Computational Notebooks

    If you are using Jupyter, VSCode Notebook, or Colab, you can call wizmap.visualize() directly within your notebook to render the map.

  3. Install and run WizMap locally

    main

    To run the WizMap web application locally for development, clone the repository, install the dependencies using npm, and start the development server.

    git clone git@github.com:poloclub/wizmap.git
    npm install
    npm run dev

    After running npm run dev, navigate to http://localhost:3000 in your browser.

  4. Format UMAP point stream data

    main

    The UMAPPointStreamData type defines the expected format for raw UMAP data arrays. The array can vary in length depending on the metadata available for each point:

    • [number, number, string]: [x, y, text]
    • [number, number, string, string]: [x, y, text, year]
    • [number, number, string, string, number]: [x, y, text, year, group]
    export type UMAPPointStreamData =
      | [number, number, string]
      | [number, number, string, string]
      | [number, number, string, string, number];
  5. Manage tooltips with the Packer class

    main

    The Packer class uses a provided Svelte tooltipStore to manage tooltip visibility and content. When a user hovers over a circle, the Packer updates the store with:

    • html: A formatted string containing the phrase label and its occurrence count.
    • x: The horizontal center position of the tooltip.
    • y: The vertical position of the tooltip.
    • show: A boolean indicating if the tooltip should be visible.

    Developers can subscribe to this store to render the tooltip UI anywhere in their application.

  6. Generate WizMap JSON files

    main

    WizMap requires two specific JSON files to function: one for the contour plot/summaries (grid_dict) and one for the raw data (data_list).

    1. Prepare Coordinates: Project your high-dimensional embeddings into 2D space (e.g., using UMAP) and extract the xs and ys coordinates.
    2. Prepare Content: Create a list of JSON strings (json_strings) where each string contains the metadata for a single point (e.g., text, image URLs, or links).
    3. Configure Content: Use wizmap.JsonPointContentConfig to map your JSON keys to WizMap's internal display logic (e.g., defining which key holds the tooltip text or the image URL).
    4. Generate and Save: Use wizmap.generate_grid_dict and wizmap.generate_data_list to create the required structures, then save them using wizmap.save_json_files.
    # 1. Define content configuration
    json_point_content_config = wizmap.JsonPointContentConfig(
        groupLabels=None,
        textKey="t",
        imageKey="i",
        imageURLPrefix="https://example.com/images/",
        largeImageKey="li",
        largeImageURLPrefix="https://example.com/images/",
        linkFieldKeys=["github"],
    )
    
    # 2. Generate the data structures
    data_list = wizmap.generate_data_list(xs, ys, json_strings)
    grid_dict = wizmap.generate_grid_dict(
        xs=xs,
        ys=ys,
        texts=json_strings,
        title="My Dataset",
        json_point_content_config=json_point_content_config,
    )
    
    # 3. Save to disk
    wizmap.save_json_files(data_list, grid_dict, output_dir="./")
  7. Generate a density grid JSON for WizMap

    main

    WizMap requires a density grid to render the background heatmap. You must compute a Kernel Density Estimation (KDE) over a regular 2D grid and export a JSON object containing the grid values, the coordinate ranges, and optional temporal grids (for time-based filtering).

    # The resulting JSON structure should look like this:
    grid_density_json = {
        'grid': grid_density.astype(float).round(4).tolist(), # 2D list of density values
        'xRange': [x_min, x_max],
        'yRange': [y_min, y_max],
        'sampleSize': sample_size,
        'totalPointSize': umap_df.shape[0],
        'padded': True,
        'timeGrids': time_grids # Dictionary mapping year strings to 2D density lists
    }
  8. Reduce embeddings with UMAP

    main

    Use UMAP to project high-dimensional embeddings into 2D space (xs, ys) for visualization. This example uses cuml for GPU-accelerated UMAP, but standard umap-learn can be used similarly. The resulting coordinates should be bundled with metadata (titles, authors, years) into a DataFrame for export.

    import cuml
    
    n_neighbors = 60
    min_dist = 0.1
    reducer_cuml = cuml.UMAP(
        n_neighbors=n_neighbors,
        min_dist=min_dist,
        metric='cosine',
        n_components=2,
        verbose=False,
        random_state=20220101
    )
    
    projected_emb_cuml = reducer_cuml.fit_transform(embeddings)
  9. Export data to NDJSON format

    main

    WizMap can consume data in NDJSON format. Each line in the file should represent a single data point, typically containing its 2D coordinates, the associated text, and optional metadata like year or title.

    # Format: [x, y, text, year, title]
    import ndjson
    
    umap_data_short = []
    for i in range(len(xs)):
        cur_row = [xs[i], ys[i], texts[i], times[i], labels[i]]
        umap_data_short.append(cur_row)
    
    with open("umap.ndjson", "w") as fp:
        ndjson.dump(umap_data_short, fp)
  10. Extract abstract embeddings using SentenceTransformer

    main

    To generate embeddings for text data (e.g., paper abstracts), use the sentence-transformers library. You can specify a device (CPU or CUDA) and encode a list of strings in batches to optimize performance.

    from sentence_transformers import SentenceTransformer
    import torch
    
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model = SentenceTransformer('all-mpnet-base-v2', device=device)
    
    abstracts = [sentence.lower() for sentence in metadata_df['abstract']]
    embeddings = model.encode(abstracts, batch_size=64, show_progress_bar=True)
  11. Configure Embedding view settings

    main

    When initializing the Embedding view, you can provide an EmbeddingInitSetting object to control the visibility of various map elements. Use the following keys:

    • showContour: boolean
    • showPoint: boolean
    • showGrid: boolean
    • showLabel: boolean
    const settings: EmbeddingInitSetting = {
      showContour: true,
      showPoint: true,
      showGrid: true,
      showLabel: true
    };