#1751·visdom

Bug: pie(), boxplot(), stem(), surf(), and contour() crash on size-1 inputs due to unconditional np.squeeze()

Author: Pcmhacker-heroCreated Aug 21, 2026Updated Aug 27, 2026

Bug Description

Several plotting methods crash with AssertionError when given size-1 inputs (e.g. a single-slice pie chart or a single-row surface plot). The root cause is an unconditional np.squeeze() call that collapses valid dimensions before the ndim assertion runs.

Steps to Reproduce

python
import visdom
import numpy as np

viz = visdom.Visdom()

# 1. Single-slice pie chart (e.g. "100% complete")
viz.pie(X=[100])
# AssertionError: X should be one-dimensional

# 2. Single-point boxplot
viz.boxplot(X=[10.5])
# AssertionError: X should be one or two-dimensional

# 3. Single-point stem plot
viz.stem(X=[5.0])
# AssertionError: X should be one or two-dimensional

# 4. Single-row surface plot (1×5 grid)
viz.surf(X=np.ones((1, 5)))
# AssertionError: X should be two-dimensional

# 5. Single-column contour plot (5×1 grid)
viz.contour(X=np.ones((5, 1)))
# AssertionError: X should be two-dimensional

Multi-element inputs work fine for all methods (e.g. pie([30, 70]), surf(np.ones((5, 5)))).

Expected Behavior

  • pie(X=[100]) should render a single-slice pie chart.
  • boxplot(X=[10.5]) should render a single-observation boxplot.
  • stem(X=[5.0]) should render a single stem.
  • surf(X=np.ones((1, 5))) and contour(X=np.ones((5, 1))) should render the 2D matrix as-is (valid Plotly z data).

Root Cause

In py/visdom/__init__.py, the affected methods call X = np.squeeze(X) unconditionally before asserting dimensionality:

Method Line What happens
pie() L3946 np.squeeze([100]) → shape (1,)() (ndim=0) → fails assert X.ndim == 1
boxplot() L3621 np.squeeze([10.5]) → shape (1,)() (ndim=0) → fails assert X.ndim == 1 or X.ndim == 2
stem() L3857 Same as boxplot
_surface() L3672 np.squeeze(np.ones((1, 5))) → shape (5,) (ndim=1) → fails assert X.ndim == 2

By contrast, violin() (L4498) uses the guarded pattern and handles size-1 inputs correctly:

python
X = np.asarray(X)
if X.ndim > 2:
    X = np.squeeze(X)

Similarly, heatmap() (L3219) does not call np.squeeze() at all, so heatmap(np.ones((1, 5))) works fine — even though it accepts the same 2D matrix format as surf() and contour().

Suggested Fix

Replace unconditional np.squeeze(X) with the guarded pattern already used by violin():

For pie() (L3946):

python
X = np.asarray(X)
if X.ndim > 1:
    X = np.squeeze(X)
if X.ndim == 0:
    X = X.reshape(1)

For boxplot() (L3621) and stem() (L3857):

python
X = np.asarray(X)
if X.ndim > 2:
    X = np.squeeze(X)

For _surface() (L3672):

python
X = np.asarray(X)
if X.ndim > 2:
    X = np.squeeze(X)

Environment

  • Visdom version: 0.2.4 (current dev branch)
  • Python: 3.12+
  • NumPy: any version (core np.squeeze behavior)
  • OS: macOS / Linux / Windows (platform-independent)