Download this notebook from GitHub (right-click to download).

import panel as pn
import pandas as pd
import numpy as np


The Perspective pane provides an interactive visualization component for large, real-time datasets built on the Perspective project.


For layout and styling related parameters see the customization user guide.

  • aggregates (dict): Aggregation spec, e.g. {x: “distinct count”}

  • columns (list): List of displayed columns.

  • expressions (list): List of expressions, e.g. ['"x"+"y"']

  • filters (list): A list of filters, e.g. [["x", "<", 3], ["y", "contains", "abc"]].

  • group_by (list): List of columns to group by, e.g. ["x", "y"]

  • object (dict or pd.DataFrame): The plot data declared as a dictionary of arrays or a DataFrame.

  • selectable (bool, default=True): Whether rows are selectable

  • split_by (list): A list of columns to pivot by. e.g. ["x", "y"]

  • sort (list): List of sorting specs, e.g. [["x", "desc"]]

  • plugin (str): The name of a plugin to display the data. For example ‘datagrid’ or ‘d3_xy_scatter’.

  • plugin_config (dict): Configuration for the PerspectiveViewerPlugin

  • toggle_config (bool): Whether to show the config menu.

  • theme (str): The theme of the viewer, available options include 'material', 'material-dark', 'material-dense', 'material-dense-dark', 'monokai', 'solarized', 'solarized-dark' and 'vaporwave'

The Perspective pane renders columns of data specified as a dictionary of lists or arrays and pandas DataFrames:

data = {'x': [1, 2, 3], 'y': [1, 2, 3]}

pn.pane.Perspective(data, width=1000)

You can also provide configuration options for the viewer plugins:

random_df = pd.DataFrame(np.random.randn(20, 2), columns=list('XY'))

pn.pane.Perspective(random_df, width=1000, plugin_config={
    'columns': {
        'X': {'gradient': 0.7836544570728833, 'neg_color': '#f07160', 'number_color_mode': 'gradient', 'pos_color': '#7dc3f0'},
        'Y': {'gradient': 1.5673089141457666, 'neg_color': '#ff9485', 'number_color_mode': 'gradient', 'pos_color': '#607785'}

We can also set the various config settings such as choosing the columns to display or the theme from Python:

df = pd.DataFrame(np.random.randn(400, 4), columns=list('ABCD')).cumsum()

stream_perspective = pn.pane.Perspective(
    df, plugin='d3_y_line', columns=['A', 'B', 'C', 'D'], theme='material-dark',
    sizing_mode='stretch_width', height=500, margin=0


The Perspective pane also supports stream and patch methods allowing us to efficiently update the data. The amount of data to keep in the streaming buffer can be controlled via the rollover option:

rollover = pn.widgets.IntInput(name='Rollover', value=500)

def stream():
    data = df.iloc[-1] + np.random.randn(4), rollover.value)

cb = pn.state.add_periodic_callback(stream, 50)

pn.Row(cb.param.period, rollover)

Alternatively we can also patch the data:

mixed_df = pd.DataFrame({'A': np.arange(10), 'B': np.random.rand(10), 'C': [f'foo{i}' for i in range(10)]})

perspective = pn.pane.Perspective(mixed_df, height=500)


The easiest way to patch the data is by supplying a dictionary as the patch value. The dictionary should have the following structure:

    column: [
        (index: int or slice, value),

As an example, below we will patch the ‘A’ and ‘C’ columns. On the 'A' column we will replace the 0th row and on the 'C' column we replace the first two rows:

perspective.patch({'A': [(0, 3)], 'C': [(slice(0, 1), 'bar')]})


Deleting rows can be achieved by streaming the data you want to become visible and setting rollover equal to the row count of new data. Effectively, deleting old rows. Removing specific rows by index in a similar manner as patching is currently not supported.

data = {'A': np.arange(10)}

perspective = pn.pane.Perspective(data, height=500)

smaller_data = {'A': np.arange(5)}, rollover=5)


The Perspective pane exposes a number of options which can be changed from both Python and Javascript try out the effect of these parameters interactively:

pn.Row(perspective.controls(jslink=True), perspective)
This web page was generated from a Jupyter notebook and not all interactivity will work on this website. Right click to download and run locally for full Python-backed interactivity.

Download this notebook from GitHub (right-click to download).