Reut
Reut

Reputation: 1592

Diagonal heatmap with matplotlib

I have a heatmap that I created from Pandas in this way:

tukey = tukey.set_index('index')
 
fix,ax = plt.subplots(figsize=(12,6))
ax.set_title(str(date)+' '+ str(hour)+':'+'00',fontsize=14)
heatmap_args = {'linewidths': 0.35, 'linecolor': '0.5', 'clip_on': False, 'square': True, 'cbar_ax_bbox': [0.75, 0.35, 0.04, 0.3]}
sp.sign_plot(tukey, **heatmap_args)

enter image description here

I have tried to do this with seaborn but I haven't gotten the desired output:

# Generate a mask for the upper triangle
mask = np.triu(np.ones_like(tukey, dtype=bool))
# Set up the matplotlib figure
f, ax = plt.subplots(figsize=(12, 6))
# Generate a custom diverging colormap
cmap = sns.diverging_palette(230, 20, as_cmap=True)
# Draw the heatmap with the mask and correct aspect ratio
sns.heatmap(tukey, mask=mask, cmap=cmap, vmax=.3, center=0,
                square=True, linewidths=.5, cbar_kws={"shrink": .5})

enter image description here

As seen, it still shows square where it is supposed to be masked and obviously the cbar is different.

My question is if there is any way to make it diagonal without using seaborn? Or at least just to get rid of the repeating part?

Edit: sample of my dataframe (the tukey):

>>>     1_a    1_b      1_c     1_d      1_e    1_f
index
1_a     1.00    0.900  0.75      0.736    0.900  0.400
1_b     0.9000  1.000  0.72      0.715    0.900  0.508
1_c     0.756   0.342  1.000     0.005    0.124  0.034
1_d     0.736   0.715  0.900     1.000    0.081  0.030 
1_e     0.900   0.900  0.804     0.793    1.000  0.475
1_f     0.400   0.508  0.036     0.030    0.475  1.000

*I might have typo mistakes , the two diagonal sides suppose to be equal.

edit: imports:

import scikit_posthocs as sp
import pandas as pd
import numpy as np
import statsmodels.api as sm
import scipy.stats as stats
from statsmodels.formula.api import ols

import matplotlib.pyplot as plt
import scipy.stats as stats

import seaborn as sns

Upvotes: 1

Views: 2069

Answers (1)

JohanC
JohanC

Reputation: 80339

scikit_posthocs' sign_plot() seems to create a QuadMesh (as does sns.heatmap). Setting an edge color to such a mesh will show horizontal and vertical lines for the full width and height of the mesh. To make the edges invisible in the "empty" region, they can be colored the same as the background (for example white). Making individual cells invisible can be done by setting their values to NaN such as in the code below.

Removing a column and a row (e.g. tukey.drop('1_f', axis=1, inplace=True) and tukey.drop('1_a', axis=0, inplace=True)), doesn't help to make the plot a bit smaller because sign_plot adds them back in automatically.

import matplotlib.pyplot as plt
import scikit_posthocs as sp
import pandas as pd
import numpy as np
from io import StringIO

data_str = '''     1_a    1_b      1_c     1_d      1_e    1_f
1_a     1.00    0.900  0.75      0.736    0.900  0.400
1_b     0.9000  1.000  0.72      0.715    0.900  0.508
1_c     0.756   0.342  1.000     0.005    0.124  0.034
1_d     0.736   0.715  0.900     1.000    0.081  0.030 
1_e     0.900   0.900  0.804     0.793    1.000  0.475
1_f     0.400   0.508  0.036     0.030    0.475  1.000'''
tukey = pd.read_csv(StringIO(data_str), delim_whitespace=True)

cols = tukey.columns
for i in range(len(cols)):
    for j in range(i, len(cols)):
        tukey.iloc[i, j] = np.nan

fix, ax = plt.subplots(figsize=(12, 6))
heatmap_args = {'linewidths': 0.35, 'linecolor': 'white', 'clip_on': False, 'square': True,
                'cbar_ax_bbox': [0.75, 0.35, 0.04, 0.3]}
sp.sign_plot(tukey, **heatmap_args)
plt.show()

resulting plot

Upvotes: 2

Related Questions