1
$\begingroup$

The given below code is not working now(earlier it was working) to put the column names on the diagonal of Seaborn PairGrid.

import matplotlib.pyplot as plt
import seaborn as sns
iris = sns.load_dataset('iris')

def diagfunc(x, **kws):
  ax = plt.gca()
  ax.annotate(x.name, xy=(0.05, 0.9), xycoords=ax.transAxes)

sns.PairGrid(iris).map_diag(diagfunc)

enter image description here

At present it showing this error!

<ipython-input-137-f4d9b71087cb> in diagfunc(x, **kws)
      5 def diagfunc(x, **kws):
      6     ax = plt.gca()
----> 7     ax.annotate(x.name, xy=(0.05, 0.9), xycoords=ax.transAxes)
      8 
      9 sns.PairGrid(iris).map_diag(diagfunc)

AttributeError: 'numpy.ndarray' object has no attribute 'name'

Can anyone help me how to put the column name in diagonal?

$\endgroup$
0
$\begingroup$

With minimal changes, I got this to work (python3.7.3, SeaBorn 0.9.0):

import matplotlib.pyplot as plt
import seaborn as sns
iris = sns.load_dataset('iris')

# Add this before your call to map_diag
next_iris_label = iter(iris).__next__

def diagfunc(x, **kws):
  ax = plt.gca()
  #  replace x.name with `next_iris_label` call
  ax.annotate(next_iris_label(), xy=(0.05, 0.9), xycoords=ax.transAxes)

sns.PairGrid(iris).map_diag(diagfunc)

Output: Output of the obove python code when run in JupyterLab

I dug into it and understood that the reason this fails is because once the IRIS dataset has been passed to SeaBorn.PairGrid, the original Names of observation columns are not retained. map_diag ends up calling diagfunc with diagonal components of the PairGrid, which do not have name property, let alone name anywhere else in the arguments passed. Here is what is passed to the first time diagfunc is called:

{
    #  this is what you passed as positional parameter
    #  As you'll notice `x` is just an array, and 
    #   does not have any additional properties like a label
    'x': array([5.1, 4.9, , ... 5.9]), 
    #  these get passed in as **kws
    'label': '_nolegend_', 
    'color': (0.12156862745098039, 0.4666666666666667, 0.7058823529411765)
}

Now, if we could somehow iterate over all labels in IRIS dataset, we could put each one against the diagnoals of the PairGrid. Since diagfunc is called each time and has a new scope, I found that having an iterator that returned a new label each time it was called solves that.

next_iris_label defined as

next_iris_label = iter(iris).__next__

solves that problem. This only has one constraint that I dont like, you will need to reset this by creating a new instance of the iterator by the binding statement next_iris_label = iter(iris).__next__ when you want to do such labelling again(otherwise it would throw a StopIteration error.)

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.