Jupyter notebooks

Chemiscope can be used as a widget in Jupyter notebooks, that should work in both Jupyter classic and JupyterLab. The widget can be created in default mode (showing both a structure and a map panel), or used to display only structures or only properties.

Once created, it is possible to interact with the widget using a traitlet interface, modeled after Jupyter widgets.

Creating a chemiscope widget

chemiscope.show(structures=None, *, properties=None, metadata=None, environments=None, shapes=None, settings=None, mode='default', warning_timeout=10000, cache_structures=True, frames=None, meta=None)

Show the dataset defined by the given structures and properties (optionally metadata, environments and shapes as well) using an embedded chemiscope visualizer inside a Jupyter notebook. These parameters have the same meaning as in the chemiscope.create_input() function.

The mode keyword also allows overriding the default two-panels visualization to show only a structure panel (mode = "structure") or the map panel (mode = "map"). These modes also make it possible to view a dataset for which properties (or structures) are not available. The widget displays warning messages, that disappear after the specified warning_timeout (in ms). Set to a negative value to disable warnings, and to zero to make them persistent. cache_structures is a flag determining whether to cache structure data on the Python side to reduce the JScript memory footprint.

When inside a jupyter notebook, the returned object will create a new chemiscope visualizer displaying the dataset. The object exposes a settings traitlet, that allows to modify the visualization options (possibly even linking the parameters to another widget). Printing the value of the settings property is also a good way to see a full list of the available options.

The returned object also have a save function that can be used to save the dataset to a .json or .json.gz file to load it in the main website later. The visualization options will be those used in the active widget, so this is also a good way to tweak the appearance of the visualization before saving it.

import chemiscope
from sklearn.decomposition import PCA
import ase.io

pca = PCA(n_components=3)

structures = ase.io.read(...)
properties = {
    "PCA": pca.fit_transform(some_data),
}

widget = chemiscope.show(structures, properties)
# display the dataset in a chemiscope visualizer inside the notebook
widget
# ...

# NB: due to how traitlet work, you should always set the value of
# the `settings` property. Only the properties that are explicitly
# indicated will be modified.
widget.settings = {"map": {"symbol": "tag"}}
widget.settings["map"]["symbol"] = "tag"  # << does nothing!

# Save the file for later use
widget.save("dataset.json")
chemiscope.show_input(path, *, settings=None, mode='default', warning_timeout=10000, cache_structures=True)

Loads and shows the chemiscope input in path.

If path ends with .gz, the file is loaded as a gzip compressed JSON string. If path is a file-like object, it is read as JSON input.

Parameters:
  • path (str | Path | file-like) – load the chemiscope input from this path or file-like object

  • settings (dict) – override the default settings in the input

  • mode (str) – widget mode, either default, structure or map.

  • warning_timeout (float) – timeout (in ms) for warnings. Set to a negative value to disable warnings, and to zero to make them persistent.

  • cache_structures (bool) – whether to cache structure data on the Python side to reduce the JScript memory footprint

import chemiscope

widget = chemiscope.show_input("dataset.json")

# or

with open("dataset.json", "r") as f:
    widget = chemiscope.show_input(f)

Widget properties and methods

The widget object returned by chemiscope.show() provides traitlets to interact with the visualization state programmatically. For more information on using traitlets and widget events (like observe), please refer to the ipywidgets documentation.

settings

A dictionary containing the current visualization settings. This traitlet is synchronized between Python and the JavaScript frontend. You can update it to change visualization options (e.g. map ranges, structure representation).

By changing the pinned setting, you can control the number of viewers shown in the grid, as well as which structures are displayed in each viewer.

# Enable space filling representation for the active viewer
widget.settings = {"structure": [{"spaceFilling": True}]}

# Set up 4 viewers with the specified structures
widget.settings = {"pinned": [0, 1, 12, 5]
selected_ids

A dictionary describing the currently selected structure or environment. It contains a structure index and optionally an atom index to indicate the active environment.

# Select the structure with index 3 and the environment 8
widget.selected_ids = {"structure": 3, "atom": 8}
active_viewer

An integer indicating the index of the currently active viewer in the grid (0-based).

Saving the dataset and settings as a standalone file

The “save” method allows exporting the current state of the widget as a standalone JSON file that can be opened in the web app (or loaded with chemiscope.show_input()).

ChemiscopeWidgetBase.save(path)

Save the dataset displayed by this widget as JSON to the given path. If path ends with .gz, the file is written as gzip compressed JSON string.

Parameters:

path (str) – where to save the dataset.

Exporting images

The chemiscope widget provides methods to capture snapshots of the map and structure panels programmatically. These methods are asynchronous, as they require communication with the browser’s JavaScript engine to render and capture the data.

There are two types of methods: save_* methods, which write the image data directly to a file given the path, and get_* methods, which return the raw image bytes (PNG formatted).

Note

These methods return asyncio.Future objects. Depending on the environment, you may be able to await directly in a cell to wait for the result. If await hangs in your environment, you can use catch the get_* return value, and then in a separate cell get .result() to access the actual return value.

Basic usage example:

# Cell 1: Create and display the widget
import chemiscope
widget = chemiscope.show(structures, properties)
widget
# Cell 2: Save a snapshot of the current map to a file
widget.save_map_image("current_map.png")
# Cell 3: Capture structure image data as raw PNG bytes
img_future = widget.get_structure_image()
# Display image
from IPython.display import Image
img_data = img_future.result()
display(Image(img_data))

Capturing sequences

You can also capture a sequence of structure snapshots (e.g., for a trajectory animation). The indices parameter can be a list of structure indices or a list of dictionaries specifying both structure and atom indices. An optional settings parameter allows applying specific visualization settings to each frame.

indices = [0, 10, 20]
paths = ["frame_0.png", "frame_10.png", "frame_20.png"]

# Capture and save a sequence of frames
widget.save_structure_sequence(indices, paths)
ChemiscopeWidgetBase.save_map_image(path)

Save a snapshot of the map to a file.

This method starts a background task to save the image. You can await it if you need to ensure the file is written before proceeding.

widget.save_map_image("map.png")
Parameters:

path (str) – Path where the image will be saved.

Returns:

A Future that resolves when the file is written.

ChemiscopeWidgetBase.save_structure_image(path)

Save a snapshot of the active structure viewer to a file.

This method starts a background task to save the image. You can await it if you need to ensure the file is written before proceeding.

widget.save_structure_image("structure.png")
Parameters:

path (str) – Path where the image will be saved.

Returns:

A Future that resolves when the file is written.

ChemiscopeWidgetBase.get_map_image()

Request a snapshot of the map. Returns a Future that resolves to the image data (PNG formatted).

This method is asynchronous. In a Jupyter notebook, you should await it to get the data.

# Get raw image data
data = await widget.get_map_image()

# Display it
from IPython.display import Image

display(Image(data))
Returns:

A Future that resolves to the image data as bytes.

ChemiscopeWidgetBase.get_structure_image()

Request a snapshot of the active structure viewer. Returns a Future that resolves to the image data (PNG formatted).

This method is asynchronous. In a Jupyter notebook, you should await it to get the data.

data = await widget.get_structure_image()
Returns:

A Future that resolves to the image data as bytes.

ChemiscopeWidgetBase.save_structure_sequence(indices, paths, settings=None)

Save a sequence of structure snapshots to files.

This method acts as a wrapper around get_structure_sequence() and writes the results to files.

indices = [0, 10, 20]
paths = ["frame_0.png", "frame_10.png", "frame_20.png"]
await widget.save_structure_sequence(indices, paths)
Parameters:
  • indices (list) – List of indices (int or dict) to render.

  • paths (list) – List of file paths where images will be saved. Must match length of indices.

  • settings (list) – Optional list of settings dicts to apply to each frame.

Returns:

A Future that resolves when all files are written.

ChemiscopeWidgetBase.get_structure_sequence(indices, settings=None)

Request a sequence of structure snapshots. Returns a Future that resolves to a list of image data (PNG formatted).

This allows rendering multiple frames efficiently without blocking the UI. The sequence is processed in the browser.

The indices list can contain integers (structure index) or dictionaries specifying structure and atom indices (for environments).

The settings list, if provided, must have the same length as indices. Each element is a dictionary of structure settings (e.g. {"spaceFilling": True}) to apply for that specific frame.

indices = [0, 1, 2]
settings = [{"spaceFilling": True}, {}, {"spaceFilling": False}]
data_list = await widget.get_structure_sequence(indices, settings)
Parameters:
  • indices (list) – List of indices (int or dict) to render.

  • settings (list) – Optional list of settings dicts to apply for each frame.

Returns:

A Future that resolves to a list of image data bytes.

Dataset exploration

chemiscope.explore(structures=None, featurizer=None, properties=None, environments=None, settings=None, mode='default', write_input=None, *, frames=None)

Automatically generate an interactive Chemiscope visualization of atomic structures.

This function creates a low-dimensional representation of the input structures and displays them using a Chemiscope widget. It supports automatic featurization with PETMADFeaturizer or a custom featurization function.

The default PETMADFeaturizer computes PET-MAD features from the structures and projects them into the 3D MAD latent space.

If available, all properties are extracted automatically from the structures.

If one does not specify a featurizer (or sets it as a None), only properties will be displayed on the map visualizer panel, as long as there are at least two of them.

Overall, the visualization can include: properties extracted from the structures, additional user-provided properties, features from either the built-in PET-MAD featurizer, with dimensionality reduction, or a custom user-provided featurization functions.

Parameters:
  • structures (list) – list of structures

  • featurizer – either string specifying a featurizer version (currently only ‘pet-mad-1.0’), a custom callable function, or None. Used to compute features and perform dimensionality reduction on the structures. For automatic default option, use pet-mad-1.0. The callable should take structures as the first argument and environments as the second argument. The return value must be a features array of shape (n_structures, n_features) if environments is None, or (n_environments, n_features) otherwise.

  • properties (dict) – optional. Additional properties to be included in the visualization. This dictionary can contain any other relevant data associated with the atomic structures. Properties can be extracted from structures with extract_properties() or manually defined by the user.

  • environments – optional. List of environments (described as (structure id, center id, cutoff)) to include when extracting the atomic properties. Can be extracted from structures with all_atomic_environments() or manually defined.

  • settings (dict) – optional dictionary of settings to use when displaying the data. Possible entries for the settings dictionary are documented in the chemiscope input file reference.

  • mode (str) – optional. Visualization mode for the chemiscope widget. Can be one of “default”, “structure”, or “map”. The default mode is “default”.

  • device (str) – torch device to use for the calculation with the default PETMADFeaturizer. If None, we will try the options in the model’s supported_device in order.

  • batch_size (int) – optional. Number of structures processed in each batch with the default PETMADFeaturizer.

  • write_input (string) – optional. A path to save the chemiscope input file created by this function. Afterwards, the file can be loaded using chemiscope.show_input()

Returns:

a chemiscope widget for interactive visualization

To use this function, additional dependencies are required, specifically, pet_mad

Returns:

a chemiscope widget for interactive visualization

To use this function, additional dependencies are required, specifically, pet-mad used for the default dimensionality reduction. They can be installed with the following command:

pip install chemiscope[explore]

Here is an example using this function with and without a featurizer function. The structures are obtained by reading the structures from a file that ase can read, and performing Kernel PCA using sklearn on a descriptor computed with SOAP using the dscribe library.

import chemiscope
import ase.io
import dscribe.descriptors
import sklearn.decomposition

# Read the structures from the dataset
structures = ase.io.read("trajectory.xyz", ":")

# 1) Basic usage with default featurizer (PET-MAD featurization + Sketch-Map)
chemiscope.explore(structures, featurizer="pet-mad-1.0")

# or
featurizer = chemiscope.get_featurizer("pet-mad-1.0")
chemiscope.explore(structures, featurizer=featurizer)


# Define a function for dimensionality reduction
def soap_kpca_featurize(structures, environments):
    if environments is not None:
        raise ValueError("'environments' are not supported by this featurizer")
    # Compute descriptors
    soap = dscribe.descriptors.SOAP(
        species=["C"],
        r_cut=4.5,
        n_max=8,
        l_max=6,
        periodic=True,
    )
    descriptors = soap.create(structures)

    # Apply KPCA
    kpca = sklearn.decomposition.KernelPCA(n_components=2, gamma=0.05)

    # Return a 2D array of reduced features
    return kpca.fit_transform(descriptors)


# 2) Example with a custom featurizer function
chemiscope.explore(structures, featurizer=soap_kpca_featurize)

For more examples, see the related documentation.

chemiscope.get_featurizer(name)

Get a featurizer by name for feature extraction. Currently available version is: “pet-mad-1.0”, which returns an instance of PETMADFeaturizer.

Parameters:

name (str) – name of the featurizer. Must match one of the known versions. Currently available is “pet-mad-1.0”

Warning

This function requires additional dependencies. Install them using:

pip install chemiscope[explore]
chemiscope.metatomic_featurizer(model, *, extensions_directory=None, check_consistency=None, device=None, length_unit='Angstrom', variant=None)

Create a featurizer function using a metatomic model to obtain the features from structures. The model must be able to create a "features" output.

Parameters:
  • model – model to use for the calculation. It can be a file path, a Python instance of metatomic.torch.AtomisticModel, or the output of torch.jit.script() on metatomic.torch.AtomisticModel.

  • extensions_directory – a directory where model extensions are located

  • check_consistency – should we check the model for consistency when running, defaults to False.

  • device – a torch device to use for the calculation. If None, the function will use the options in model’s supported_device attribute.

  • length_unit – Unit of length used in the structures.

  • variant – selects which feature output variant to use. By default, the main "features" output is used. To choose another variant, provide its name (e.g., "cos_sin"), which will select the corresponding "features/<variant>" output.

Returns:

a function that takes a list of structures and returns the features.

To use this function, additional dependencies are required. They can be installed with the following command:

pip install chemiscope[explore]

Here is an example using a pre-trained metatomic model, stored as a model.pt file with the compiled extensions stored in the extensions/ directory. The structures are obtained by reading structures from a file that ase can read.

import chemiscope
import ase.io

# Read the structures from the dataset
structures = ase.io.read("data/explore_c-gap-20u.xyz", ":")

# Provide model file ("model.pt") to `metatensor_featurizer`
featurizer = chemiscope.metatensor_featurizer(
    "model.pt", extensions_directory="extensions"
)

chemiscope.explore(structures, featurizer=featurizer)

For more examples, see the related documentation.