Search code examples
matplotliblabelpie-chart

Is there a way to label each wedge of pie chart in this grid?


I want to have multiple pie charts in a grid.

Each pie chart will have a different number of wedges, values, and labels.

The code below shows multiple labels in one pie chart.

Is there a way to label each wedge of pie-charts in this grid?

import matplotlib.pyplot as plt
import numpy as np

def heatmap_with_circles(data_array,row_labels,column_labels,ax=None, cmap=None, norm=None, cbar_kw={}, cbarlabel="", **kwargs):

    for row_index, row in enumerate(row_labels,0):
        for column_index, column in enumerate(column_labels,0):
            print('row_index: %d column_index: %d' %(row_index,column_index))
            if row_index==0 and column_index==0:
                colors=['indianred','orange','gray']
                values=[10,20,30]
            else:
                values=[45,20,38]
                colors=['pink','violet','green']

            wedges, text = plt.pie(values,labels=['0', '2', '3'],labeldistance = 0.25,colors=colors)
            print('len(wedges):%d wedges: %s, text: %s' %(len(wedges), wedges, text))
            radius = 0.45
            [w.set_center((column_index,row_index)) for w in wedges]
            [w.set_radius(radius) for w in wedges]

    # We want to show all ticks...
    ax.set_xticks(np.arange(data_array.shape[1]))
    ax.set_yticks(np.arange(data_array.shape[0]))

    fontsize=10
    ax.set_xticklabels(column_labels, fontsize=fontsize)
    ax.set_yticklabels(row_labels, fontsize=fontsize)

    #X axis labels at top
    ax.tick_params(top=True, bottom=False,labeltop=True, labelbottom=False,pad=5)
    plt.setp(ax.get_xticklabels(), rotation=55, ha="left", rotation_mode="anchor")

    # We want to show all ticks...
    ax.set_xticks(np.arange(data_array.shape[1]+1)-.5, minor=True)
    ax.set_yticks(np.arange(data_array.shape[0]+1)-.5, minor=True)

    ax.grid(which="minor", color="black", linestyle='-', linewidth=2)
    ax.tick_params(which="minor", bottom=False, left=False)

data_array=np.random.rand(3,4)
row_labels=['Row1', 'Row2', 'Row3']
column_labels=['Column1', 'Column2', 'Column3','Column4']

fig, ax = plt.subplots(figsize=(1.9*len(column_labels),1.2*len(row_labels)))
ax.set_aspect(1.0)
ax.set_facecolor('white')
heatmap_with_circles(data_array,row_labels,column_labels, ax=ax)
plt.tight_layout()
plt.show()

enter image description here

After updating heatmap_with_circles

def heatmap_with_circles(data_array,row_labels,column_labels,ax=None, cmap=None, norm=None, cbar_kw={}, cbarlabel="", **kwargs):
    labels = ['x', 'y', 'z']

    for row_index, row in enumerate(row_labels,0):
        for column_index, column in enumerate(column_labels,0):
            print('row_index: %d column_index: %d' %(row_index,column_index))
            if row_index==0 and column_index==0:
                colors=['indianred','orange','gray']
                values=[10,20,30]
            else:
                values=[45,20,38]
                colors=['pink','violet','green']

            # wedges, texts = plt.pie(values,labels=['0', '2', '3'],labeldistance = 0.45,colors=colors)
            wedges, texts = plt.pie(values,labeldistance = 0.25,colors=colors)
            print('text:%s len(wedges):%d wedges: %s' %(texts, len(wedges), wedges))
            radius = 0.45
            [w.set_center((column_index,row_index)) for w in wedges]
            [w.set_radius(radius) for w in wedges]
            [text.set_position((text.get_position()[0]+column_index,text.get_position()[1]+row_index)) for text in texts]
            [text.set_text(labels[text_index]) for text_index, text in enumerate(texts,0)]

enter image description here

I got the following image :)


Solution

  • You could loop through the texts of each pie, get its xy position, add column_index and row_index, and set that as new position.

    Some small changes to the existing code:

    • ax.grid(which="minor", ..., clip_on=False) to make sure the thick lines are shown completely, also near the border
    • ax.set_xlim(xmin=-0.5) to set the limits
    import matplotlib.pyplot as plt
    import numpy as np
    
    def heatmap_with_circles(data_array, row_labels, column_labels, ax=None):
        ax = ax or plt.gca()
        for row_index, row in enumerate(row_labels, 0):
            for column_index, column in enumerate(column_labels, 0):
                colors = np.random.choice(['indianred', 'orange', 'gray', 'pink', 'violet', 'green'], 3, replace=False)
                values = np.random.randint(10, 41, 3)
                wedges, text = plt.pie(values, labels=['1', '2', '3'], labeldistance=0.25, colors=colors)
                radius = 0.45
                for w in wedges:
                    w.set_center((column_index, row_index))
                    w.set_radius(radius)
                    w.set_edgecolor('white')
                    # w.set_linewidth(1)
                for t in text:
                    x, y = t.get_position()
                    t.set_position((x + column_index, y + row_index))
    
        # We want to show all ticks...
        ax.set_xticks(np.arange(data_array.shape[1]))
        ax.set_yticks(np.arange(data_array.shape[0]))
    
        fontsize = 10
        ax.set_xticklabels(column_labels, fontsize=fontsize)
        ax.set_yticklabels(row_labels, fontsize=fontsize)
    
        # X axis labels at top
        ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False, pad=5)
        plt.setp(ax.get_xticklabels(), rotation=55, ha="left", rotation_mode="anchor")
    
        # We want to show all minor ticks...
        ax.set_xticks(np.arange(data_array.shape[1] + 1) - .5, minor=True)
        ax.set_yticks(np.arange(data_array.shape[0] + 1) - .5, minor=True)
        ax.set_xlim(xmin=-.5)
        ax.set_ylim(ymin=-.5)
    
        ax.grid(which="minor", color="black", linestyle='-', linewidth=2, clip_on=False)
        ax.tick_params(axis="both", which="both", length=0) # hide tick marks
    
    data_array = np.random.rand(3, 4)
    row_labels = ['Row1', 'Row2', 'Row3']
    column_labels = ['Column1', 'Column2', 'Column3', 'Column4']
    
    fig, ax = plt.subplots(figsize=(1.9 * len(column_labels), 1.2 * len(row_labels)))
    ax.set_aspect(1.0)
    ax.set_facecolor('white')
    heatmap_with_circles(data_array, row_labels, column_labels, ax=ax)
    plt.tight_layout()
    plt.show()
    

    pie chart grid with labels