Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions GPy/examples/stick_explorer_spike.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Deprecated. The stick explorer moved to vidden.

Install https://github.com/lawrennd/vidden and run::

from vidden.explore import stick_explorer
stick_explorer()

or from that repository::

panel serve examples/stick.py --show
"""

from __future__ import annotations

import warnings

_MSG = (
"GPy.examples.stick_explorer_spike has moved to the vidden package. "
"Install vidden (https://github.com/lawrennd/vidden) and import "
"vidden.explore, or run `panel serve examples/stick.py --show` there."
)

warnings.warn(_MSG, DeprecationWarning, stacklevel=2)

try:
from vidden.explore import stick_explorer
except ImportError as exc:
raise ImportError(_MSG) from exc

__all__ = ["stick_explorer"]
43 changes: 42 additions & 1 deletion GPy/plotting/matplot_dep/visualize.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,43 @@
import numpy as np
"""Deprecated interactive latent-space viewers (matplotlib / VPython).

This module is the 2012–2015 mouse explorer for GPLVM reconstructions
(``lvm``, ``lvm_dimselect``, ``image_show``, ``vector_show``,
``stick_show``, ``skeleton_show``, ``data_play``). It is deprecated.

Matplotlib GUI callbacks do not work reliably on macOS or Jupyter, and
interactive visualisation does not belong in the core inference library.
Use `vidden <https://github.com/lawrennd/vidden>`_ instead.

Static GPy plots (``plot``, ``plot_latent``, ``plot_confidence``) are
unchanged. Comments welcome on the deprecation discussion:
https://github.com/SheffieldML/GPy/discussions/1252
"""

import time
import warnings

import numpy as np

from ...core.parameterization.variational import VariationalPosterior

_VISUALIZE_DEPRECATED = (
"GPy.plotting.matplot_dep.visualize is deprecated and will be removed. "
"Interactive latent-space viewers (lvm, lvm_dimselect, image_show, "
"vector_show, stick_show, skeleton_show, data_play) rely on matplotlib "
"GUI callbacks that do not work reliably on macOS or Jupyter, and "
"interactive visualisation does not belong in the core inference library. "
"Use vidden: https://github.com/lawrennd/vidden "
"Static GPy plots (plot, plot_latent, plot_confidence) are unchanged. "
"Comments welcome: https://github.com/SheffieldML/GPy/discussions/1252"
)


def _warn_visualize_deprecated(stacklevel=2):
warnings.warn(_VISUALIZE_DEPRECATED, DeprecationWarning, stacklevel=stacklevel)


_warn_visualize_deprecated(stacklevel=2)

try:
import matplotlib.pyplot as plt
import matplotlib as mpl
Expand All @@ -23,6 +59,7 @@ class data_show:
"""

def __init__(self, vals):
_warn_visualize_deprecated(stacklevel=3)
self.vals = vals.copy()
# If no axes are defined, create some.

Expand Down Expand Up @@ -609,6 +646,9 @@ def wrap_around(self, lim, connect):
def data_play(Y, visualizer, frame_rate=30):
"""Play a data set using the data_show object given.

Deprecated. See the module docstring and
https://github.com/SheffieldML/GPy/discussions/1252

:Y: the data set to be visualized.
:param visualizer: the data show objectwhether to display during optimisation
:type visualizer: data_show
Expand All @@ -626,6 +666,7 @@ def data_play(Y, visualizer, frame_rate=30):
GPy.util.visualize.data_play(Y, visualize)

"""
_warn_visualize_deprecated(stacklevel=2)

for y in Y:
visualizer.modify(y[None, :])
Expand Down
45 changes: 45 additions & 0 deletions GPy/testing/test_stick_explorer_spike.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import importlib
import warnings

import numpy as np


def _deprecated_visualize_warnings(caught):
return [
item
for item in caught
if issubclass(item.category, DeprecationWarning)
and "vidden" in str(item.message)
and "discussions/1252" in str(item.message)
]


def test_visualize_import_warns_and_points_at_vidden():
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always", DeprecationWarning)
mod = importlib.import_module("GPy.plotting.matplot_dep.visualize")
importlib.reload(mod)
assert _deprecated_visualize_warnings(caught)
message = str(_deprecated_visualize_warnings(caught)[0].message)
assert "macOS" in message or "macos" in message.lower()
assert "core inference library" in message


def test_visualize_constructor_warns_and_points_at_discussion():
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always", DeprecationWarning)
mod = importlib.import_module("GPy.plotting.matplot_dep.visualize")
importlib.reload(mod)
mod.data_show(np.zeros((1, 3)))
assert _deprecated_visualize_warnings(caught)


def test_stick_explorer_spike_warns_and_points_at_vidden():
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always", DeprecationWarning)
try:
importlib.import_module("GPy.examples.stick_explorer_spike")
except ImportError as exc:
assert "vidden" in str(exc)
return
assert any(issubclass(item.category, DeprecationWarning) and "vidden" in str(item.message) for item in caught)
59 changes: 59 additions & 0 deletions backlog/documentation/2026-10-26_latent-explorer-example-docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
id: 2026-10-26_latent-explorer-example-docs
title: Latent explorer example notebook and serve notes
status: Ready
priority: Low
created: "2026-10-26"
last_updated: "2026-10-26"
category: documentation
related_cips:
- "000B"
owner: Neil Lawrence
dependencies:
- 2026-10-26_explore-module-optional-extra
tags:
- backlog
- documentation
- plotting
- jupyter
---

# Task: Latent explorer example docs

> Backlog task for [CIP-000B](../../cip/cip000B.md). Informal docs only;
> Sphinx compression waits until the CIP is Closed.

## Description

Add one notebook or example script that shows:

- `pip install 'gpy[explore]'` (or the extra name chosen in the module task)
- Jupyter use
- `panel serve` for a standalone window

Keep it short. Do not write a Sphinx tutorial until CIP-000B is Closed and
compressed.

The doodle notebook on `notebook-latent-doodle-space` is out of scope.

## Acceptance Criteria

- [ ] Example lives in `notebooks/` or `GPy/examples/` and imports the explore API
- [ ] README or example docstring states Jupyter vs `panel serve`
- [ ] No Sphinx page yet (compression is a later CIP-close step)

## Implementation Notes

- Prefer reusing the stick spike as the documented example.
- Optional extra must be mentioned so a default GPy install is not assumed.

## Related

- CIP: 000B
- Depends: 2026-10-26_explore-module-optional-extra

## Progress Updates

### 2026-10-26

Task created when CIP-000B was Accepted.
67 changes: 67 additions & 0 deletions backlog/features/2026-10-26_explore-module-optional-extra.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
id: 2026-10-26_explore-module-optional-extra
title: Add GPy.plotting.explore module and optional extra
status: Abandoned
priority: High
created: "2026-10-26"
last_updated: "2026-10-27"
category: features
related_cips:
- "000B"
owner: Neil Lawrence
dependencies:
- 2026-10-26_panel-stick-explorer-spike
tags:
- backlog
- plotting
- packaging
- holoviews
---

# Task: Explore module and optional extra

> Backlog task for [CIP-000B](../../cip/cip000B.md). Depends on the Panel spike.

## Description

Extract the spike into a small public module so demos share one explorer.
Keep GPy models ignorant of the UI: latent point in, `predict` out, viewer
pane for `Y`.

Provisional names (lock them here if the spike suggests better ones):

- `GPy.plotting.explore.latent_explorer`
- `image_view`, `vector_view`, `stick_view`

Add a Poetry extra (e.g. `gpy[explore]`) for HoloViews and Panel. Default
`pip install gpy` must not pull them.

## Acceptance Criteria

- [ ] Module importable when the extra is installed
- [ ] Import of `GPy` and `GPy.plotting` succeeds without HoloViews/Panel
- [ ] Unit tests for reconstruct helpers on `Agg` with a tiny GPLVM
- [ ] Explorer tests skip via `pytest.importorskip` when the extra is absent
- [ ] Extra declared in `pyproject.toml`

## Implementation Notes

- Do not add HoloViews/Panel to core or to `gpy[plotting]` (matplotlib/plotly).
- Tests must not start a GUI or a browser driver.
- Stick view can live here; Plotly 3D skeleton is a later task.

## Related

- CIP: 000B
- Depends: 2026-10-26_panel-stick-explorer-spike

## Progress Updates

### 2026-10-26

Task created when CIP-000B was Accepted.

### 2026-10-27

Abandoned. The explorer is not a GPy extra. It lives in
https://github.com/lawrennd/vidden (vidden CIP-0001).
75 changes: 75 additions & 0 deletions backlog/features/2026-10-26_panel-stick-explorer-spike.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
id: 2026-10-26_panel-stick-explorer-spike
title: Panel spike for stick_bgplvm latent explorer
status: Completed
priority: High
created: "2026-10-26"
last_updated: "2026-10-27"
category: features
related_cips:
- "000B"
owner: Neil Lawrence
dependencies: []
tags:
- backlog
- plotting
- panel
- holoviews
- gplvm
---

# Task: Panel spike for stick_bgplvm

> Backlog task for [CIP-000B](../../cip/cip000B.md). No public API yet.

## Description

Prove that a browser explorer can replace matplotlib `lvm_dimselect` on macOS.
Build a Panel app around `stick_bgplvm(optimize=False)`: latent scatter, stick
reconstruction from `model.predict`, and two widgets to choose which latent
axes to plot. Other latent dimensions stay at the posterior mean.

Do this in an example or notebook on this branch. Do not add
`GPy.plotting.explore` or a Poetry extra until the spike works.

## Acceptance Criteria

- [x] Pointer (or tap) in the latent scatter updates the stick figure via `predict`
- [x] Two dim selectors change which latent axes are plotted
- [ ] Works in Jupyter on macOS without the matplotlib `macosx` GUI backend
- [x] Same app runs with `panel serve`
- [x] No new core GPy dependency

## Implementation Notes

- HoloViews `PointerXY` / `Tap` plus Panel layout, as sketched in CIP-000B.
- BayesianGPLVM latents are `m.X.mean`; copy to a writable `(1, Q)` array
before writing the two active coordinates.
- Reuse stick connectivity from `pods.datasets.osu_run1()["connect"]`.
- Keep the spike throwaway-friendly; the next task extracts the module.

## Related

- CIP: 000B
- Demo: `GPy.examples.dimensionality_reduction.stick_bgplvm`

## Progress Updates

### 2026-10-26

Task created when CIP-000B was Accepted.

Spike app in `GPy/examples/stick_explorer_spike.py`. `panel serve` on macOS shows
the latent scatter, Plotly stick reconstruction, and dim selectors. Changing the
y-axis from 1 to 2 updates the scatter. Pointer position is written into
`predict`. Jupyter still needs a manual check:

```python
from GPy.examples.stick_explorer_spike import stick_explorer
stick_explorer()
```

### 2026-10-27

Completed by moving the spike to vidden (`vidden.explore`,
`examples/stick.py`). GPy's file is a deprecation stub.
Loading
Loading