pythonpandasmatplotlibmatplotlibpyplot

How can I adjust the white empty space around a Matplotlib table to match the table size?


There's extra white, empty space around my Matplotlib table, causing my table to get squished as if the figsize wasn't big enough. If I increase the figsize, the table displays normally, but then the white, empty space gets even bigger. Additionally, the title gets misplaced over the table when the number of rows passes a certain number (around 35 or so).

import matplotlib.pyplot as plt

def create_pivot_table(
        title: str,
        pivot_table: pd.core.frame.DataFrame,
):
    """
    Creates a Matplotlib table from a Pandas pivot table.
    Returns fig and ax.
    """

    fig_width = 1 + len(pivot_table.columns) * 0.6
    fig_height = 1 + len(pivot_table) * 0.3
    figsize=(fig_width, fig_height)
    fig, ax = plt.subplots(figsize=figsize)

    title = title
    ax.set_title(
        title,
        fontsize=16,
        weight='bold',
        loc='center'
    )
    ax.axis('off')

    table = ax.table(
        cellText=pivot_table.values,
        colLabels=pivot_table.columns,
        rowLabels=pivot_table.index,
        cellLoc='center',
        loc='center'
    )

    table.auto_set_font_size(False)

    # Formatting the table with alternating colors to make it more readable
    for (row, column), cell in table.get_celld().items():
        if row == 0:
            cell.set_text_props(weight='bold')
            cell.set_fontsize(8)
            cell.set_height(0.05)

            if column % 2 == 0:
                cell.set_facecolor('#dadada')
            else:
                cell.set_facecolor('#ffffff')
        else:
            cell.set_fontsize(10)
            cell.set_height(0.03)

            if row % 2 == 0:
                cell.set_facecolor('#ffffff')
            else:
                cell.set_facecolor('#e6f7ff')

            if column % 2 == 0:
                cell.set_facecolor('#dadada' if row % 2 == 0 else '#b9d5d3')
            else:
                cell.set_facecolor('#ffffff' if row % 2 == 0 else '#e6f7ff')

    return fig, ax

Dummy data:

import pandas as pd
import numpy as np

data = np.random.randint(1, 100, size=(3, 4))
df = pd.DataFrame(data, index=['A', 'B', 'C'], columns=[1, 2, 3, 4])

title = 'Title'

fig, ax = create_pivot_table(
    title=title,
    pivot_table=df
)

Result:

Resulting table

Desired outcome: the same table, minus the empty white space, so the table displays correctly. Additionally, I'd like to center the title and table within the figure, which does not happen with the code I wrote (depending on the table and title size).

Thanks in advance for the help!


Solution

  • I think you need to try suptitle for title and play with bbox parameter of table.

    import matplotlib.pyplot as plt
    import pandas as pd
    import numpy as np
    
    def create_pivot_table(
            title: str,
            pivot_table: pd.core.frame.DataFrame,
    ):
        """
        Creates a Matplotlib table from a Pandas pivot table.
        Returns fig and ax.
        """
    
        fig_width = 1 + len(pivot_table.columns) * 0.6
        fig_height = 1 + len(pivot_table) * 0.3
        figsize=(fig_width, fig_height)
        fig, ax = plt.subplots(figsize=figsize)
    
        fig.suptitle(title, fontsize=16, weight='bold', y=0.95)
    
        ax.axis('off')
    
        table = ax.table(
            cellText=pivot_table.values,
            colLabels=pivot_table.columns,
            rowLabels=pivot_table.index,
            cellLoc='center',
            loc='center',
            bbox=[0,0,1,0.95]
        )
    
        table.auto_set_font_size(False)
    
        # Formatting the table with alternating colors to make it more readable
        for (row, column), cell in table.get_celld().items():
            if row == 0:
                cell.set_text_props(weight='bold')
                cell.set_fontsize(8)
                cell.set_height(0.05)
    
                if column % 2 == 0:
                    cell.set_facecolor('#dadada')
                else:
                    cell.set_facecolor('#ffffff')
            else:
                cell.set_fontsize(10)
                cell.set_height(0.03)
    
                if row % 2 == 0:
                    cell.set_facecolor('#ffffff')
                else:
                    cell.set_facecolor('#e6f7ff')
    
                if column % 2 == 0:
                    cell.set_facecolor('#dadada' if row % 2 == 0 else '#b9d5d3')
                else:
                    cell.set_facecolor('#ffffff' if row % 2 == 0 else '#e6f7ff')
    
        return fig, ax
    
    data = np.random.randint(1, 100, size=(3, 4))
    df = pd.DataFrame(data, index=['A', 'B', 'C'], columns=[1, 2, 3, 4])
    
    title = 'Title'
    
    fig, ax = create_pivot_table(
        title=title,
        pivot_table=df
    )
    
    plt.show()