Bug: pie(), boxplot(), stem(), surf(), and contour() crash on size-1 inputs due to unconditional np.squeeze()
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
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-dimensionalMulti-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)))andcontour(X=np.ones((5, 1)))should render the 2D matrix as-is (valid Plotlyzdata).
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:
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):
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):
X = np.asarray(X)
if X.ndim > 2:
X = np.squeeze(X)For _surface() (L3672):
X = np.asarray(X)
if X.ndim > 2:
X = np.squeeze(X)Environment
- Visdom version: 0.2.4 (current
devbranch) - Python: 3.12+
- NumPy: any version (core
np.squeezebehavior) - OS: macOS / Linux / Windows (platform-independent)
Source: fossasia/visdom