mwaskom / seaborn

Statistical data visualization in Python
https://seaborn.pydata.org
BSD 3-Clause "New" or "Revised" License
12.39k stars 1.91k forks source link

seaborn.matrix.clustermap Runtime error in Jupyter Notebook #3265

Open mucmch opened 1 year ago

mucmch commented 1 year ago

When running the following sample code in a Jupyter Notebook, there is a RuntimeError. However, it is highly dependent on the cell order within the Jupyter Notebook.

Environment:

Jupyter notebook server: 6.5.2 Python 3.10.8 IPython 8.8.0 Seaborn: 0.11.2

Sample Code:

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from seaborn.matrix import clustermap

data = pd.DataFrame(np.random.randn(300, 300))

grid = clustermap(data)
fig = plt.gcf()
fig.show()

Error Stack


RuntimeError Traceback (most recent call last) Cell In[23], line 8 4 from seaborn.matrix import clustermap 6 data = pd.DataFrame(np.random.randn(300, 300)) ----> 8 grid = clustermap(data) 9 fig = plt.gcf() 10 fig.show()

File ~\anaconda3\envs\dev\lib\site-packages\seaborn_decorators.py:46, in _deprecate_positional_args..inner_f(*args, kwargs) 36 warnings.warn( 37 "Pass the following variable{} as {}keyword arg{}: {}. " 38 "From version 0.12, the only valid positional argument " (...) 43 FutureWarning 44 ) 45 kwargs.update({k: arg for k, arg in zip(sig.parameters, args)}) ---> 46 return f(kwargs)

File ~\anaconda3\envs\dev\lib\site-packages\seaborn\matrix.py:1406, in clustermap(data, pivot_kws, method, metric, z_score, standard_scale, figsize, cbar_kws, row_cluster, col_cluster, row_linkage, col_linkage, row_colors, col_colors, mask, dendrogram_ratio, colors_ratio, cbar_pos, tree_kws, kwargs) 1248 """ 1249 Plot a matrix dataset as a hierarchically-clustered heatmap. 1250 (...) 1398 >>> g = sns.clustermap(iris, z_score=0, cmap="vlag") 1399 """ 1400 plotter = ClusterGrid(data, pivot_kws=pivot_kws, figsize=figsize, 1401 row_colors=row_colors, col_colors=col_colors, 1402 z_score=z_score, standard_scale=standard_scale, 1403 mask=mask, dendrogram_ratio=dendrogram_ratio, 1404 colors_ratio=colors_ratio, cbar_pos=cbar_pos) -> 1406 return plotter.plot(metric=metric, method=method, 1407 colorbar_kws=cbar_kws, 1408 row_cluster=row_cluster, col_cluster=col_cluster, 1409 row_linkage=row_linkage, col_linkage=col_linkage, 1410 tree_kws=tree_kws, kwargs)

File ~\anaconda3\envs\dev\lib\site-packages\seaborn\matrix.py:1232, in ClusterGrid.plot(self, metric, method, colorbar_kws, row_cluster, col_cluster, row_linkage, col_linkage, tree_kws, kws) 1229 yind = np.arange(self.data2d.shape[0]) 1231 self.plot_colors(xind, yind, kws) -> 1232 self.plot_matrix(colorbar_kws, xind, yind, **kws) 1233 return self

File ~\anaconda3\envs\dev\lib\site-packages\seaborn\matrix.py:1203, in ClusterGrid.plot_matrix(self, colorbar_kws, xind, yind, kws) 1198 else: 1199 # Turn the colorbar axes off for tight layout so that its 1200 # ticks don't interfere with the rest of the plot layout. 1201 # Then move it. 1202 self.ax_cbar.set_axis_off() -> 1203 self._figure.tight_layout(tight_params) 1204 self.ax_cbar.set_axis_on() 1205 self.ax_cbar.set_position(self.cbar_pos)

File ~\anaconda3\envs\dev\lib\site-packages\matplotlib\figure.py:3444, in Figure.tight_layout(self, pad, h_pad, w_pad, rect) 3441 engine = TightLayoutEngine(pad=pad, h_pad=h_pad, w_pad=w_pad, 3442 rect=rect) 3443 try: -> 3444 self.set_layout_engine(engine) 3445 engine.execute(self) 3446 finally:

File ~\anaconda3\envs\dev\lib\site-packages\matplotlib\figure.py:2586, in Figure.set_layout_engine(self, layout, **kwargs) 2584 self._layout_engine = new_layout_engine 2585 else: -> 2586 raise RuntimeError('Colorbar layout of new layout engine not ' 2587 'compatible with old engine, and a colorbar ' 2588 'has been created. Engine not changed.')

RuntimeError: Colorbar layout of new layout engine not compatible with old engine, and a colorbar has been created. Engine not changed.

mwaskom commented 1 year ago

I can't replicate this with the following versions

seaborn 0.13.0.dev0
matplotlib 3.7.0

What version of matplotlib are you using? Can you try on the most recent released versions of seaborn / matplotlib?

mucmch commented 1 year ago

I found the culprit. The 'figure.constrained_layout.use' was still activated in the background. Probably some explicit enabling and disabling or at least some explicit error handling would be helpful.

The error can be reproduced like:

import matplotlib as mpl
import numpy as np
from seaborn.matrix import clustermap

data = np.random.randn(300, 300)
mpl.rcParams['figure.constrained_layout.use'] = True
grid = clustermap(data)
mwaskom commented 1 year ago

Ah, I see. Yeah; could probably avoid it using this: https://github.com/mwaskom/seaborn/blob/242a3312b6742f5b255c7ad6bccb7228839c9419/seaborn/utils.py#L852

(Although I think this needs to be expanded to include the newer layout-related parameters).

Nagidrop commented 1 month ago

I have the same problem using constrained_layout. However, using tight_layout (rcParams['figure.autolayout'] = True) works without any errors.

Given constrained_layout supposed to be a more flexible version of tight_layout and handles colorbars placed on multiple Axes, maybe we can narrow down and just debug around that code section?