cuxfilter.md
605 lines · skills/optimize-for-gpu/references/cuxfilter.md at 5f2bc03
cuxfilter Reference
Review: 2026-10-01. Code below is illustrative unless explicitly described as CPU-tested. GPU execution, performance, GDS, and multi-GPU behavior require validation on target hardware.
cuxfilter is a GPU-accelerated cross-filtering dashboard library from the NVIDIA RAPIDS ecosystem. It enables interactive, multi-chart exploratory data analysis dashboards from Jupyter notebooks in just a few lines of Python. All filtering, groupby, and aggregation operations happen on the GPU via cuDF, with only the visualization results sent to the browser.
Full documentation: https://docs.rapids.ai/api/cuxfilter/stable/ Version (stable): 26.06.00 (final release) Repository: https://github.com/rapidsai/cuxfilter
⚠️ Project status: sunset. cuxfilter has been sunset — v26.06 is the final release and no packages will be published for later RAPIDS releases (see RSN 60). The examples below target the isolated 26.06 API and are not a guarantee of compatibility with current dependencies; for new projects RAPIDS recommends composing dashboards directly from maintained libraries instead: cuDF for GPU data loading/aggregation plus HoloViews / hvPlot / Datashader for linked cross-filtering visualizations, served with Panel, Plotly Dash, Streamlit, or Bokeh.Raw lines 1 to 13
Table of Contents
- Installation and Setup
- Core Concepts
- DataFrame: Loading Data
- Charts
- Widgets
- Dashboard Creation
- Layouts
- Themes
- Dashboard Display and Export
- Graph Visualization
- Multi-GPU with Dask-cuDF
- Interoperability
- Performance Tips
- Common Patterns
Raw lines 14 to 32
Installation and Setup
Use uv add in standalone examples; follow the user's existing project package manager when one is already configured.
uv add --extra-index-url=https://pypi.nvidia.com "cuxfilter-cu12==26.6.*" # For CUDA 12.x
uv add --extra-index-url=https://pypi.nvidia.com "cuxfilter-cu13==26.6.*" # For CUDA 13.xBoth install the final 26.06 release — no further updates will be published. cuxfilter wheels are also on PyPI directly, so the extra index is optional. cuxfilter depends on matching cuDF 26.06. Keep the entire legacy stack isolated from RAPIDS 26.08 and pandas 3.
Platform: Linux and WSL2 only (no native macOS or Windows). Requires: NVIDIA GPU with CUDA 12.x or 13.x support, Python 3.11+.
Verify:
import cuxfilter
import cudf
df = cudf.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
cux_df = cuxfilter.DataFrame.from_dataframe(df)
print(cux_df.data.head()) # Should print GPU dataframeRaw lines 33 to 59
Core Concepts
cuxfilter has five main modules:
- **
cuxfilter.DataFrame** — Wraps a cuDF DataFrame for dashboard use. Entry point for creating dashboards. - **
cuxfilter.DashBoard** — The interactive dashboard object. Created from a DataFrame with charts. - **
cuxfilter.charts** — Chart factory functions (bar, scatter, line, heatmap, choropleth, graph, widgets). - **
cuxfilter.layouts** — Preset and custom layout configurations for chart arrangement. - **
cuxfilter.themes** — Visual themes for dashboards (default, dark, rapids, rapids_dark).
The workflow is always: Load data → Create charts → Build dashboard → Display.
Raw lines 60 to 73
DataFrame: Loading Data
The cuxfilter.DataFrame is the starting point. It wraps a cuDF or dask_cudf DataFrame.
From a cuDF DataFrame (most common)
import cudf
import cuxfilter
cudf_df = cudf.DataFrame({
"x": [0, 1, 2, 3, 4],
"y": [10.0, 11.0, 12.0, 13.0, 14.0],
"category": ["A", "B", "A", "B", "A"]
})
cux_df = cuxfilter.DataFrame.from_dataframe(cudf_df)Raw lines 78 to 90From an Arrow file on disk
cux_df = cuxfilter.DataFrame.from_arrow("data/my_dataset.arrow")Raw lines 91 to 95From a graph (nodes + edges)
import cugraph
edges = cudf.DataFrame({"source": [0, 1, 2], "target": [1, 2, 3], "weight": [1.0, 2.0, 3.0]})
G = cugraph.Graph()
G.from_cudf_edgelist(edges, source="source", destination="target", edge_attr="weight")
positions = cugraph.force_atlas2(G)
cux_df = cuxfilter.DataFrame.load_graph((positions, edges))Or directly from cuDF DataFrames:
nodes = cudf.DataFrame({"vertex": [0, 1, 2, 3], "x": [0, 1, 2, 3], "y": [4, 4, 2, 6], "attr": [0, 1, 1, 1]})
edges = cudf.DataFrame({"source": [0, 1, 2], "target": [1, 2, 3], "weight": [1.0, 2.0, 3.0]})
cux_df = cuxfilter.DataFrame.load_graph((nodes, edges))Raw lines 96 to 113Accessing the underlying data
cux_df.data # The cuDF DataFrame
cux_df.data["new_col"] = cux_df.data["x"] * 2 # Add columns before creating dashboardRaw lines 114 to 121
Charts
All chart functions are accessed via cuxfilter.charts. They use the top-level shorthand — you do NOT need to import submodules like cuxfilter.charts.bokeh or cuxfilter.charts.datashader directly.
Bar Chart (Bokeh)
chart = cuxfilter.charts.bar(
x="column_name", # Required: x-axis column
y=None, # Optional: y-axis column (defaults to count)
data_points=None, # Number of bins (None = nunique)
add_interaction=True, # Enable cross-filtering interaction
aggregate_fn="count", # 'count' or 'mean'
step_size=None, # Step size for range slider
title="", # Chart title
autoscaling=True, # Auto-scale y-axis on data update
)Raw lines 126 to 139Line Chart (Bokeh)
chart = cuxfilter.charts.line(
x="x_col",
y="y_col",
data_points=100,
add_interaction=True,
)Raw lines 140 to 149Scatter Plot (Datashader — handles millions of points)
chart = cuxfilter.charts.scatter(
x="x_col",
y="y_col",
aggregate_col=None, # Column for color aggregation
aggregate_fn="count", # 'count', 'mean', 'max', 'min'
color_palette=None, # Bokeh palette or list of hex colors
point_size=15,
pixel_shade_type="eq_hist", # 'eq_hist', 'linear', 'log', 'cbrt'
pixel_density=0.5, # [0, 1], higher = denser
pixel_spread="dynspread", # 'dynspread' or 'spread'
tile_provider=None, # Map tile (e.g., "CartoLight" for geo data)
title="",
unselected_alpha=0.2, # Transparency of unselected points
)Raw lines 150 to 167Heatmap (Datashader)
chart = cuxfilter.charts.heatmap(
x="x_col",
y="y_col",
aggregate_col="value_col",
aggregate_fn="mean", # 'count', 'mean', 'max', 'min'
color_palette=None,
point_size=10,
point_shape="rect_vertical", # 'circle', 'square', 'rect_vertical', 'rect_horizontal'
title="",
)Raw lines 168 to 181Stacked Lines (Datashader)
chart = cuxfilter.charts.stacked_lines(
x="time_col",
y=["series_a", "series_b", "series_c"], # List of y columns
colors=["red", "green", "blue"],
)Raw lines 182 to 190Choropleth (Deck.gl — 2D and 3D maps)
chart = cuxfilter.charts.choropleth(
x="zip_code",
color_column="metric_col",
color_aggregate_fn="mean", # 'count', 'mean', 'sum', 'min', 'max', 'std'
elevation_column="value_col", # Set for 3D choropleth, omit for 2D
elevation_factor=0.00001,
elevation_aggregate_fn="sum",
geoJSONSource="https://url/to/geojson",
geo_color_palette=None, # Default: Inferno256
nan_color="#d3d3d3",
tooltip=True,
tooltip_include_cols=["zip_code", "metric_col"],
title="",
)Raw lines 191 to 208Graph (Datashader — node-link diagrams)
chart = cuxfilter.charts.datashader.graph(
node_x="x", # Default "x"
node_y="y", # Default "y"
node_id="vertex", # Default "vertex"
edge_source="source", # Default "source"
edge_target="target", # Default "target"
node_aggregate_col=None,
node_color_palette=None,
edge_color_palette=["#000000"],
node_point_size=15,
node_pixel_shade_type="eq_hist",
edge_render_type="direct", # 'direct' or 'curved' (curved is experimental)
edge_transparency=0, # [0, 1]
tile_provider=None,
title="",
unselected_alpha=0.2,
)Raw lines 209 to 231
Widgets
Widgets provide interactive filtering controls, typically placed in the sidebar.
Raw lines 232 to 235Number (KPI indicator)
widget = cuxfilter.charts.number(
expression="column_name", # Or a computed expression like "(x + y) / 2"
aggregate_fn="mean", # 'count', 'mean', 'min', 'max', 'sum', 'std'
title="Average Value",
format="{value:.2f}", # Python format string
colors=[(33, "green"), (66, "gold"), (100, "red")], # Threshold coloring
font_size="18pt",
)Raw lines 266 to 277Card (Markdown content)
import panel as pn
widget = cuxfilter.charts.card(pn.pane.Markdown("## My Dashboard\nSome description text"))Raw lines 278 to 285
Dashboard Creation
Create a dashboard by calling .dashboard() on a cuxfilter DataFrame:
# Define charts and widgets
chart1 = cuxfilter.charts.scatter(x="x_col", y="y_col")
chart2 = cuxfilter.charts.bar("category_col")
sidebar_widget = cuxfilter.charts.range_slider("value_col")
number_widget = cuxfilter.charts.number(expression="value_col", aggregate_fn="mean", title="Mean Value")
# Build dashboard
d = cux_df.dashboard(
charts=[chart1, chart2], # Main area charts
sidebar=[sidebar_widget, number_widget], # Sidebar widgets
layout=cuxfilter.layouts.feature_and_base,
theme=cuxfilter.themes.rapids_dark,
title="My Dashboard",
data_size_widget=True, # Show current data count
)Raw lines 286 to 307Adding charts after creation
new_chart = cuxfilter.charts.line("x_col", "y_col")
d.add_charts(charts=[new_chart])
# or
d.add_charts(sidebar=[cuxfilter.charts.card(pn.pane.Markdown("# Note"))])Raw lines 308 to 317
Layouts
Raw lines 318 to 319Preset Layouts
| Layout | Description | Charts |
|---|---|---|
layouts.single_feature | One chart fills the page | 1 |
layouts.feature_and_base | Large chart on top, smaller below (66/33 split) | 2 |
layouts.double_feature | Two charts side-by-side | 2 |
layouts.left_feature_right_double | One large left, two stacked right | 3 |
layouts.triple_feature | Three charts in a row | 3 |
layouts.feature_and_double_base | One large top, two below | 3 |
layouts.two_by_two | 2x2 grid | 4 |
layouts.feature_and_triple_base | One large top, three below | 4 |
layouts.feature_and_quad_base | One large top, four below | 5 |
layouts.feature_and_five_edge | One large center, five around | 6 |
layouts.two_by_three | 2x3 grid | 6 |
layouts.double_feature_quad_base | Two large top, four below | 6 |
layouts.three_by_three | 3x3 grid | 9 |
Custom Layouts with layout_array
Use layout_array for full control. It's a list-of-lists where each inner list is a row, and numbers refer to chart indices (1-based):
# Chart 1 spans the left two columns; chart2 spans upper-right; charts3/4 are below
d = cux_df.dashboard(
charts_list,
layout_array=[[1, 1, 2, 2], [1, 1, 3, 4]],
theme=cuxfilter.themes.rapids_dark,
)Rules:
- Each number maps to a chart (1 = first chart, 2 = second, etc.)
- Repeating a number across cells makes that chart span those cells
- The array is auto-scaled to fit the screen
Raw lines 338 to 357
Themes
Four built-in themes:
| Theme | Description |
|---|---|
cuxfilter.themes.default | Light theme (default) |
cuxfilter.themes.dark | Dark theme |
cuxfilter.themes.rapids | RAPIDS-branded light theme |
cuxfilter.themes.rapids_dark | RAPIDS-branded dark theme |
d = cux_df.dashboard(charts, theme=cuxfilter.themes.rapids_dark)Raw lines 358 to 374
Dashboard Display and Export
Raw lines 375 to 376Display as a separate web app (opens new browser tab)
d.show()
# or with custom URL/port
d.show(notebook_url="http://localhost:8888", port=8050)Raw lines 382 to 388Export filtered data
After interacting with the dashboard (selecting ranges, filtering), export the current filtered DataFrame:
filtered_df = d.export() # Returns cuDF DataFrame matching current filter state
# Also prints the query string, e.g.: "2 <= key <= 4"Raw lines 399 to 406Graph Visualization
cuxfilter integrates with cuGraph for interactive graph visualization:
import cuxfilter
import cudf
import cugraph
# Create graph
edges = cudf.DataFrame({
"source": [0, 0, 1, 1, 2],
"target": [1, 2, 2, 3, 3]
})
G = cugraph.Graph()
G.from_cudf_edgelist(edges, source="source", destination="target")
# Load into cuxfilter (needs node positions — use force_atlas2 or similar layout)
positions = cugraph.force_atlas2(G)
nodes = positions.rename(columns={"vertex": "vertex", "x": "x", "y": "y"})
cux_df = cuxfilter.DataFrame.load_graph((nodes, edges))
# Create graph chart
chart = cuxfilter.charts.datashader.graph(
node_pixel_shade_type="linear",
unselected_alpha=0.2,
)
d = cux_df.dashboard([chart], layout=cuxfilter.layouts.single_feature)
d.app()Raw lines 414 to 448
Multi-GPU with Dask-cuDF
cuxfilter works seamlessly with dask_cudf.DataFrame — just pass it in place of a cuDF DataFrame:
import dask_cudf
ddf = dask_cudf.read_parquet("large_dataset/*.parquet")
cux_df = cuxfilter.DataFrame.from_dataframe(ddf)
# Everything else is the same
chart = cuxfilter.charts.scatter(x="x", y="y")
d = cux_df.dashboard([chart])
d.app()Use dask_cudf when:
- Data doesn't fit in a single GPU's memory
- You want to distribute across multiple GPUs
- Processing many files at once
Supported chart types with dask_cudf:
- bokeh: bar, line
- datashader: scatter, line, stacked_lines, heatmap, graph (limited edge rendering)
- panel_widgets: all widgets
- deckgl: choropleth (2D and 3D)
Raw lines 449 to 477
Interoperability
cuxfilter sits at the visualization layer of the RAPIDS ecosystem:
- cuDF — The data layer. cuxfilter.DataFrame wraps cuDF DataFrames.
- cuGraph — Graph analytics. Use
cuxfilter.DataFrame.load_graph()to visualize cuGraph results. - cuML — Run cuML, then visualize results (e.g., UMAP embeddings, cluster assignments) with cuxfilter.
- HoloViz ecosystem — Built on Panel, Bokeh, Datashader, and HoloViews.
- Deck.gl — WebGL-powered choropleth maps.
Typical RAPIDS + cuxfilter pipeline
import cudf
import cuml
import cuxfilter
# Load and preprocess with cuDF
df = cudf.read_parquet("data.parquet")
df = df.dropna().reset_index(drop=True)
# Run ML with cuML (e.g., UMAP for dimensionality reduction)
from cuml.manifold import UMAP
umap = UMAP(n_components=2, output_type="cupy")
embedding = umap.fit_transform(df[["feature1", "feature2", "feature3"]])
df["umap_x"] = embedding[:, 0]
df["umap_y"] = embedding[:, 1]
# This illustrative input must also contain a cluster_label column for the charts below.
# Visualize with cuxfilter
cux_df = cuxfilter.DataFrame.from_dataframe(df)
scatter = cuxfilter.charts.scatter(
x="umap_x", y="umap_y",
aggregate_col="cluster_label",
aggregate_fn="mean",
pixel_shade_type="linear",
)
bar = cuxfilter.charts.bar("cluster_label")
d = cux_df.dashboard([scatter, bar], layout=cuxfilter.layouts.feature_and_base)
d.app()Raw lines 488 to 520
Performance Tips
- Keep data on GPU. Load with
cudf.read_parquet()orcudf.read_csv(), then wrap withcuxfilter.DataFrame.from_dataframe(). Avoid converting to/from pandas.
- Use appropriate chart types for data size:
- < 10K points: Bokeh charts (bar, line) work well
- 10K–100M+ points: Datashader charts (scatter, heatmap) handle large datasets efficiently via server-side rasterization
- Limit data_points for bar charts. For columns with many unique values, set
data_pointsto bin them (e.g.,bar("col", data_points=50)).
- **Use
float32when possible.** GPU operations are faster with 32-bit floats. Cast before loading:df["col"] = df["col"].astype("float32").
- Pre-compute derived columns before creating the dashboard, not inside chart callbacks.
- **Use
layout_array** for complex dashboards to control exactly where each chart appears.
- **Increase
timeout** for datashader charts if zooming feels laggy on very large datasets.
Raw lines 521 to 540
Common Patterns
Raw lines 541 to 542Exploratory data analysis dashboard
import cudf
import cuxfilter
df = cudf.read_parquet("dataset.parquet")
cux_df = cuxfilter.DataFrame.from_dataframe(df)
# Overview charts
scatter = cuxfilter.charts.scatter(x="feature1", y="feature2", pixel_shade_type="linear")
hist1 = cuxfilter.charts.bar("feature1", data_points=50)
hist2 = cuxfilter.charts.bar("category")
# Sidebar filters
slider = cuxfilter.charts.range_slider("value_col")
dropdown = cuxfilter.charts.drop_down("category")
kpi = cuxfilter.charts.number(expression="value_col", aggregate_fn="mean", title="Mean Value")
d = cux_df.dashboard(
[scatter, hist1, hist2],
sidebar=[slider, dropdown, kpi],
layout=cuxfilter.layouts.feature_and_double_base,
theme=cuxfilter.themes.rapids_dark,
title="Data Explorer",
)
d.app()Raw lines 543 to 570Geospatial dashboard with scatter on map tiles
chart = cuxfilter.charts.scatter(
x="x_mercator", # Preproject longitude/latitude to EPSG:3857 meters
y="y_mercator",
aggregate_col="value",
aggregate_fn="mean",
color_palette=["#3182bd", "#6baed6", "#ff0068"],
tile_provider="CartoLight",
pixel_shade_type="linear",
title="Geo Scatter",
)Raw lines 571 to 584Time series dashboard
line_chart = cuxfilter.charts.line("timestamp", "metric")
bar_chart = cuxfilter.charts.bar("hour_of_day")
date_slider = cuxfilter.charts.date_range_slider("timestamp")
d = cux_df.dashboard(
[line_chart, bar_chart],
sidebar=[date_slider],
layout=cuxfilter.layouts.feature_and_base,
)Raw lines 585 to 597Export filtered subset for further analysis
# After user interacts with dashboard, export current selection
d.app()
# ... user filters data in the dashboard ...
filtered = d.export() # cuDF DataFrame of currently visible/selected data
# Continue analysis with cuDF, cuML, etc.Raw lines 598 to 605