Search code examples
pythonpandasseaborn

Pandas seaborn heatmap: text label horizontal


Iam new to the seaborn library. I created a heatmap for cohort analysis. The text of y label is vertical. Instead I would love to show the text label horizontal. Thanks a lot for your support - Much appreciated. The red marked should be rotated, so the text is horizontal. I think this is not exactly y label.

**dataframe: df_cohort**
        cohort  order_month n_customers period_number
1   0   2023-01 2023-01 1018    0
2   1   2023-01 2023-02 384 1
3   2   2023-01 2023-03 502 2
4   3   2023-01 2023-04 423 3
5   4   2023-01 2023-05 468 4
6   5   2023-01 2023-06 371 5
7   6   2023-01 2023-07 332 6
8   7   2023-01 2023-08 226 7
9   8   2023-01 2023-09 351 8
10  9   2023-01 2023-10 321 9
11  10  2023-01 2023-11 262 10
12  11  2023-01 2023-12 221 11
13  12  2023-02 2023-02 621 0
14  13  2023-02 2023-03 179 1
15  14  2023-02 2023-04 205 2
16  15  2023-02 2023-05 235 3
17  16  2023-02 2023-06 184 4
18  17  2023-02 2023-07 142 5
19  18  2023-02 2023-08 84  6
20  19  2023-02 2023-09 166 7
21  20  2023-02 2023-10 157 8
22  21  2023-02 2023-11 102 9
23  22  2023-02 2023-12 92  10
24  23  2023-03 2023-03 412 0
25  24  2023-03 2023-04 111 1
26  25  2023-03 2023-05 124 2
27  26  2023-03 2023-06 112 3
28  27  2023-03 2023-07 72  4
29  28  2023-03 2023-08 42  5
30  29  2023-03 2023-09 88  6
31  30  2023-03 2023-10 69  7
32  31  2023-03 2023-11 56  8
33  32  2023-03 2023-12 43  9
34  33  2023-04 2023-04 211 0
35  34  2023-04 2023-05 48  1
36  35  2023-04 2023-06 50  2
37  36  2023-04 2023-07 43  3
38  37  2023-04 2023-08 25  4
39  38  2023-04 2023-09 40  5
40  39  2023-04 2023-10 35  6
41  40  2023-04 2023-11 26  7
42  41  2023-04 2023-12 16  8
43  42  2023-05 2023-05 171 0
44  43  2023-05 2023-06 41  1
45  44  2023-05 2023-07 32  2
46  45  2023-05 2023-08 23  3
47  46  2023-05 2023-09 37  4
48  47  2023-05 2023-10 35  5
49  48  2023-05 2023-11 24  6
50  49  2023-05 2023-12 14  7
51  50  2023-06 2023-06 139 0
52  51  2023-06 2023-07 23  1
53  52  2023-06 2023-08 18  2
54  53  2023-06 2023-09 34  3
55  54  2023-06 2023-10 24  4
56  55  2023-06 2023-11 33  5
57  56  2023-06 2023-12 16  6
58  57  2023-07 2023-07 80  0
59  58  2023-07 2023-08 16  1
60  59  2023-07 2023-09 18  2
61  60  2023-07 2023-10 14  3
62  61  2023-07 2023-11 9   4
63  62  2023-07 2023-12 16  5
64  63  2023-08 2023-08 31  0
65  64  2023-08 2023-09 8   1
66  65  2023-08 2023-10 12  2
67  66  2023-08 2023-11 8   3
68  67  2023-08 2023-12 6   4
69  68  2023-09 2023-09 84  0
70  69  2023-09 2023-10 16  1
71  70  2023-09 2023-11 20  2
72  71  2023-09 2023-12 13  3
73  72  2023-10 2023-10 60  0
74  73  2023-10 2023-11 14  1
75  74  2023-10 2023-12 9   2
76  75  2023-11 2023-11 35  0
77  76  2023-11 2023-12 3   1
78  77  2023-12 2023-12 43  0


cohort_pivot = df_cohort.pivot_table(index = 'cohort',
                                     columns = 'period_number',
                                     values = 'n_customers')
cohort_size = cohort_pivot.iloc[:,0]
retention_matrix = cohort_pivot.divide(cohort_size, axis = 0)
with sns.axes_style("white"):
    fig, ax = plt.subplots(1, 2, figsize=(12, 9), sharey=True, gridspec_kw={'width_ratios': [1, 11]})
    
    # retention matrix
    sns.heatmap(retention_matrix, 
                mask=retention_matrix.isnull(), 
                annot=True, 
                fmt='.0%', 
                cmap='RdYlGn', 
                ax=ax[1])
    ax[1].set_title('Monthly Cohorts: User Retention', fontsize=16)
    ax[1].set(xlabel='# of periods',
              ylabel='')

    # cohort size
    cohort_size_df = pd.DataFrame(cohort_size).rename(columns={0: 'cohort_size'})
    white_cmap = mcolors.ListedColormap(['white'])
    sns.heatmap(cohort_size_df, 
                annot=True, 
                cbar=False, 
                fmt='g', 
                cmap=white_cmap, 
                ax=ax[0])

    fig.tight_layout()

enter image description here


Solution

  • To rotate ticklabels, you'll need to rotate them manually or use the pyplot.setp helper function. You may also need to set their horizontal alignment parameter to 'right' to ensure they line up correctly after rotating.

    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots()
    
    #...
    
    # approach (recommended matplotlib)
    ax.tick_params(axis='y', which='major', rotation=0)
    
    # approach 1
    for label in ax.get_yticklabels():
        label.set(rotation=0, ha='right')
    
    # approach 2
    plt.setp(ax.get_yticklabels(), rotation=0, ha='right')
    

    Adding that into your code snippet with some randomly generated data produces:

    import matplotlib.pyplot as plt
    import matplotlib.colors as mcolors
    from numpy.random import default_rng
    import pandas as pd
    import seaborn as sns
    
    rng = default_rng(0)
    retention_matrix = pd.DataFrame(rng.random(100).reshape(10, 10))
    cohort_size = pd.Series(
        rng.integers(10, 100, size=len(retention_matrix)),
        index=pd.date_range('2000-01', freq='MS', periods=10).strftime('%Y-%m')
    )
    
    
    with sns.axes_style("white"):
        fig, ax = plt.subplots(1, 2, figsize=(12, 9), sharey=True, gridspec_kw={'width_ratios': [1, 11]})
    
        # retention matrix
        sns.heatmap(retention_matrix,
                    mask=retention_matrix.isnull(),
                    annot=True,
                    fmt='.0%',
                    cmap='RdYlGn',
                    ax=ax[1])
        ax[1].set_title('Monthly Cohorts: User Retention', fontsize=16)
        ax[1].set(xlabel='# of periods',
                  ylabel='')
    
        # cohort size
        cohort_size_df = pd.DataFrame(cohort_size).rename(columns={0: 'cohort_size'})
        white_cmap = mcolors.ListedColormap(['white'])
        sns.heatmap(cohort_size_df,
                    annot=True,
                    cbar=False,
                    fmt='g',
                    cmap=white_cmap,
                    ax=ax[0])
        ax[0].tick_params(axis='y', which='major', rotation=0)
    
        fig.tight_layout()
        plt.show()
    

    enter image description here