Skip to content

cbook._reshape_2D flattens ndarray with 2 dims (rectangular ndarray) #8092

Description

@lcapalleja

Bug report

boxplot throwing an error (below) when x is an ndarray with len(x.shape)==2 (I.E. when x is rectangular).

ValueError: List of boxplot statistics and 'positions' values must have same the length

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt

a = np.array([np.array([1, 2, 3, 4]), np.array([3, 2, 7, 4]), np.array([3, 9, 3, 1, 6])]) 
b = np.array([np.array([1, 2, 3, 4]), np.array([3, 2, 7, 4]), np.array([3, 9, 3, 1])]) 

# Ragged ndarray works correctly
plt.boxplot(x=a, positions=range(len(a)))

# Rectangular ndarray throws error (above)
plt.boxplot(x=b, positions=range(len(b)))

Matplotlib version

  • matplotlib 1.5.3 np111py35_0
  • python 3.5.2
  • Windows Server 2012 R2 Standard
  • conda installation

Possible cause

I believe the issue is in cbook._reshape_2D in the line below. I am not sure why that logic is in place but assume it is for good reason.

X = [X[:, i] for i in xrange(ncols)]

Got there by looking in:

  1. _axes.boxplot
  2. _axes.bxp
  3. cbook.boxplot_stats

reference _reshape_2D:

def _reshape_2D(X):
    """
    Converts a non-empty list or an ndarray of two or fewer dimensions
    into a list of iterable objects so that in

        for v in _reshape_2D(X):

    v is iterable and can be used to instantiate a 1D array.
    """
    if hasattr(X, 'shape'):
        # one item
        if len(X.shape) == 1:
            if hasattr(X[0], 'shape'):
                X = list(X)
            else:
                X = [X, ]

        # several items
        elif len(X.shape) == 2:
            nrows, ncols = X.shape
            if nrows == 1:
                X = [X]
            elif ncols == 1:
                X = [X.ravel()]
            else:
                X = [X[:, i] for i in xrange(ncols)]
        else:
            raise ValueError("input `X` must have 2 or fewer dimensions")

    if not hasattr(X[0], '__len__'):
        X = [X]
    else:
        X = [np.ravel(x) for x in X]

    return X

Current Workaround
Converting the ndarray to a list of lists. The necessity for this workaround doesn't really make sense especially since the plotting works fine with a ragged/non-rectangular ndarray but does not work with a rectangular ndarray.

Metadata

Metadata

Assignees

No one assigned

    Labels

    API: consistencyConsistency of the matplotlib API, including naming, behavior, defaults, …keepItems to be ignored by the “Stale” Github Action

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions