Search code examples
pythonsparse-matrix

Trying to make a graph from a sparse matrix: not enough values to unpack (expected 2, got 0)


So I'm trying to make a graph with squares that are colored according to probability densities stored in the 7x7 matrix 'nprob'.

nprob = prob/sum
print(nprob.todense())

x,y = np.meshgrid(np.arange(0,7,1),np.arange(0,7,1)) 
fig, dens = plt.subplots()
dens.set_title('probability density for...')
dens.set_xlabel('i')
dens.set_ylabel('t')
m = dens.pcolormesh(x, y, nprob[x,y], cmap = 'Blues', shading='auto')
cbar=plt.colorbar(m)

I get the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-132-6d9dfcd16dcc> in <module>
      9 dens.set_xlabel('i')
     10 dens.set_ylabel('t')
---> 11 m = dens.pcolormesh(x, y, nprob[x,y], cmap = 'Blues', shading='auto')
     12 cbar=plt.colorbar(m)

/opt/miniconda3/lib/python3.8/site-packages/matplotlib/__init__.py in inner(ax, data, *args, **kwargs)
   1445     def inner(ax, *args, data=None, **kwargs):
   1446         if data is None:
-> 1447             return func(ax, *map(sanitize_sequence, args), **kwargs)
   1448 
   1449         bound = new_sig.bind(ax, *args, **kwargs)

/opt/miniconda3/lib/python3.8/site-packages/matplotlib/axes/_axes.py in pcolormesh(self, alpha, norm, cmap, vmin, vmax, shading, antialiased, *args, **kwargs)
   6090         kwargs.setdefault('edgecolors', 'None')
   6091 
-> 6092         X, Y, C, shading = self._pcolorargs('pcolormesh', *args,
   6093                                             shading=shading, kwargs=kwargs)
   6094         Ny, Nx = X.shape

/opt/miniconda3/lib/python3.8/site-packages/matplotlib/axes/_axes.py in _pcolorargs(self, funcname, shading, *args, **kwargs)
   5583                 if isinstance(Y, np.ma.core.MaskedArray):
   5584                     Y = Y.data
-> 5585             nrows, ncols = C.shape
   5586         else:
   5587             raise TypeError(f'{funcname}() takes 1 or 3 positional arguments '

ValueError: not enough values to unpack (expected 2, got 0)

To be honest, I get this error a lot, and I usually just rejuggle things until I get one I understand better, so it's probably about time to learn what it means. What isn't clear? I want it to graph the probability density at the 49 specified points on the grid.


Solution

  • Make a sample sparse matrix (you could have provided one :( ):

    In [31]: from scipy import sparse
    In [32]: nprob = sparse.csr_matrix(np.eye(7))
    In [33]: nprob
    Out[33]: 
    <7x7 sparse matrix of type '<class 'numpy.float64'>'
        with 7 stored elements in Compressed Sparse Row format>
    In [34]: nprob.A
    Out[34]: 
    array([[1., 0., 0., 0., 0., 0., 0.],
           [0., 1., 0., 0., 0., 0., 0.],
           [0., 0., 1., 0., 0., 0., 0.],
           [0., 0., 0., 1., 0., 0., 0.],
           [0., 0., 0., 0., 1., 0., 0.],
           [0., 0., 0., 0., 0., 1., 0.],
           [0., 0., 0., 0., 0., 0., 1.]])
    In [35]: x,y = np.meshgrid(np.arange(0,7,1),np.arange(0,7,1))
    

    Note what your indexing does - not much - it's still as csr matrix:

    In [36]: nprob[x,y]
    Out[36]: 
    <7x7 sparse matrix of type '<class 'numpy.float64'>'
        with 7 stored elements in Compressed Sparse Row format>
    

    Now your plot:

    In [37]: fig, dens = plt.subplots()
        ...: dens.set_title('probability density for...')
        ...: dens.set_xlabel('i')
        ...: dens.set_ylabel('t')
    Out[37]: Text(0, 0.5, 't')
    In [38]: m = dens.pcolormesh(x, y, nprob[x,y], cmap = 'Blues', shading='auto')
    Traceback (most recent call last):
      File "<ipython-input-38-62cf80a40eaf>", line 1, in <module>
        m = dens.pcolormesh(x, y, nprob[x,y], cmap = 'Blues', shading='auto')
      File "/usr/local/lib/python3.8/dist-packages/matplotlib/__init__.py", line 1438, in inner
        return func(ax, *map(sanitize_sequence, args), **kwargs)
      File "/usr/local/lib/python3.8/dist-packages/matplotlib/axes/_axes.py", line 6093, in pcolormesh
        X, Y, C, shading = self._pcolorargs('pcolormesh', *args,
      File "/usr/local/lib/python3.8/dist-packages/matplotlib/axes/_axes.py", line 5582, in _pcolorargs
        nrows, ncols = C.shape
    ValueError: not enough values to unpack (expected 2, got 0)
    

    But what if we plot the dense version of that matrix:

    In [39]: m = dens.pcolormesh(x, y, nprob[x,y].A, cmap = 'Blues', shading='auto')
        
    

    It works.

    plt doesn't know anything (special) about sparse matrices. I suspect it is just doing:

    In [41]: np.array(nprob)
    Out[41]: 
    array(<7x7 sparse matrix of type '<class 'numpy.float64'>'
        with 7 stored elements in Compressed Sparse Row format>, dtype=object)
    In [42]: _.shape
    Out[42]: ()
    

    That's a 0d object dtype array, not a 2d array that the plot function expects.