Jupyter Scatter Documentation

website·Indexed 32 days ago

https://jupyter-scatter.dev

A library for creating interactive scatter plots in Jupyter notebooks. Features include point and cluster selection, linked multiple scatter plots, custom axes and legends, annotations, tooltips, and connected scatterplots. Includes a comprehensive API reference for the Scatter class, widget view model, and plotting shorthand.

Tokens
16.4K
Snippets
97
Records
124
Agent score
64%

What's inside Jupyter Scatter

  1. Overview of Jupyter Scatter

    Jupyter Scatter is a scalable, interactive, and interlinked scatter plot widget designed for exploring datasets with up to several million data points within Jupyter Lab, Jupyter Notebook, and Google Colab. It supports two-way pan+zoom and lasso interactions, and can synchronize views and point selections across multiple plots. It integrates with Pandas, Polars, and any Arrow-compatible DataFrame.
  2. Create an Overview+Detail interface

    An Overview+Detail interface can be created by linking two scatter plots where selecting points in the 'Overview' plot filters the 'Detail' plot, and the 'Detail' plot automatically zooms to those filtered points.
    from jscatter import Scatter, compose
    from numpy.random import rand
    
    x, y = rand(500), rand(500)
    
    sc_overview = Scatter(x, y)
    # Detail plot zooms automatically when filtered
    sc_detail = Scatter(x, y, zoom_on_filter=True, zoom_padding=1)
    
    def filter_on_select(change):
        # Filter detail plot based on overview selection
        sc_detail.filter(change['new'] if len(change['new']) > 0 else None)
    
    sc_overview.widget.observe(filter_on_select, names='selection')
    
    compose(
        [(sc_overview, "Overview"), (sc_detail, "Detail")],
        sync_hover=True,
    )
  3. Create a basic connected scatterplot with jscatter

    Connected scatterplots are used to visualize the evolution of variables by connecting points. This is most common for temporal or time-series data. To connect points, use the connect_by parameter in the jscatter.Scatter constructor to specify the column that defines the groups to be connected.
    import jscatter
    import numpy as np
    import pandas as pd
    
    # Sample data with date, value, and group
    df = pd.DataFrame({
        'date': dates * 3,
        'value': np.concatenate((np.random.rand(12), np.random.rand(12) + 0.5, np.random.rand(12) + 1), axis=0),
        'group': ['A'] * 12 + ['B'] * 12 + ['C'] * 12,
    })
    
    scatter = jscatter.Scatter(
        data=df,
        x='date',
        x_scale='time',
        y='value',
        connect_by='group'
    )
    scatter.show()
  4. Animate point coordinates dynamically

    When updating x/y coordinates using the functional API, if the number of points remains the same, Jupyter Scatter will animate the transition between the old and new locations.
    # Mirror points along the diagonal via animation
    scatter.xy('speed', 'mass')
  5. Observe selection changes automatically

    You can react to selection changes in real-time by observing the selection property of the scatter.widget. This is useful for updating other UI elements or data views when a user interacts with the plot using the lasso tool.
    import ipywidgets
    import jscatter
    
    scatter = jscatter.Scatter(data=df, x="mass", y="speed")
    output = ipywidgets.Output()
    
    @output.capture(clear_output=True)
    def selection_change_handler(change):
        # change.new contains the list of currently selected indices
        display(df.loc[change.new])
                
    # Observe the 'selection' property of the widget
    scatter.widget.observe(selection_change_handler, names=["selection"])
    
    ipywidgets.HBox([scatter.show(), output])
  6. Select multiple points using the Lasso tool

    To select multiple points using the freeform lasso:

    1. Click and hold the primary mouse button. An open circle appears and closes clockwise.
    2. Once the circle turns blue, the lasso is active.
    3. Move the cursor around the desired points while still holding the primary mouse button.
    4. Release the mouse button to complete the selection.

    Permanent Activation: Click the crosshair icon in the top-left of the scatter plot to keep the lasso active.

    Modifying Selections:

    • Add points: Hold the meta key (Cmd/⌘ on macOS) while lassoing.
    • Remove points: Hold the alt key (Option/⌥ on macOS) while lassoing.
  7. Navigate and interact with Jupyter Scatter plots using the mouse

    Jupyter Scatter plots support several default mouse interactions for exploration:

    • Pan: Click and hold the primary mouse button and drag.
    • Zoom: Use the mouse scroll wheel.
    • Hover: Mouse over a point to display a reticle.
    • Select Point: Click on a point to select it.
    • Deselect All: Double-click into the background (the 'void').
  8. Arrange multiple scatter plots using compose()

    Use jscatter.compose() to display multiple scatter plot instances in a layout. By default, plots are arranged in a single row. You can customize the layout by specifying the number of rows and the height of each row in pixels.
    import jscatter
    import numpy as np
    
    x, y = np.random.rand(500), np.random.rand(500)
    a, b = jscatter.Scatter(x=x, y=y), jscatter.Scatter(x=x, y=y)
    
    # Default: single row
    jscatter.compose([a, b])
    
    # Custom: 2 rows
    jscatter.compose([a, b], rows=2)
    
    # Custom: 2 rows with specific height (240px)
    jscatter.compose([a, b], rows=2, row_height=240)
  9. Retrieve currently selected points

    To get the indices of the points currently selected (either via the lasso tool or programmatically), call the scatter.selection() method without any arguments. These indices can be used to slice the original DataFrame using .loc.
    # Get indices of selected points
    selected_indices = scatter.selection()
    
    # Retrieve the original data records for those indices
    selected_data = df.loc[selected_indices]
  10. Precompute and persist label placements for performance

    For large datasets, use the LabelPlacement class to precompute label positions and save them to disk as Parquet files. This avoids recomputing labels across different scenarios. The precomputed instance can be passed directly to a scatter plot using the using parameter in scatter.labels().

    Note: LabelPlacement uses a default tile size of 256x256 pixels for collision resolution. If your widget height differs, labels may appear differently unless you use the 'constant' scale function.

    from jupyter_scatter import LabelPlacement
    
    # 1. Precompute labels
    labels = LabelPlacement(data=df, x='x', y='y', by='cat')
    labels.compute(show_progress=True) # show_progress requires pip install "jupyter-scatter[all]"
    
    # 2. Persist to disk
    labels.to_parquet('my_labels')
    
    # 3. Load from disk
    labels.from_parquet('my_labels')
    
    # 4. Apply to scatter instance
    scatter.labels(using=labels)