Search code examples
pythonmatplotlibhistogrampie-chart

Combining two figures elegantly in matplotlib


Hi I have an issue for displaying then saving neatly a 7 subplot figure using matplotlib. The figure is composed of pie chart on the first row and histograms on the second one.

I have managed to get something working but I cannot manage to have something that reaches good readability when trying to get all subplot in one figure. The important thing is to be able to output one png file with all the components when saving the file.

This first example is 'correct' but generate wide space between the pie charts and the histograms:

1figure_wide_space

Here is a code 'example' (despite not exactly being what I have this is the closest working example to the problem that I can share):

histo_1 = np.random.choice(500, 100, replace=True)
histo_2 = np.random.choice(250, 7000, replace=True)
histo_3 = np.random.choice(150, 1500, replace=True)
histo_4 = np.random.choice(2000, 250, replace=True)

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]

f = plt.figure(figsize = (14, 15))
sn.set()
sn.color_palette("hls", 8)

ax = f.add_subplot(2,4,1)
plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
plt.title("Distribution")

ax = f.add_subplot(2,4,2)
plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
plt.title("Distribution")

ax = f.add_subplot(2,4,3)
plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
plt.title("Distribution")

ax = f.add_subplot(2,4,5)
plt.hist(histo_1, bins='fd', color = "cornflowerblue", edgecolor='white', linewidth=1.2)
plt.title("Distribution 1")

ax1 = f.add_subplot(2,4,6)
plt.hist(histo_2, bins='fd', color = "indianred", edgecolor='white', linewidth=1.2)
plt.title("Distribution 2")

ax2 = f.add_subplot(2,4,7)
plt.hist(histo_3, bins='fd', color = "seagreen", edgecolor='white', linewidth=1.2)
plt.title("Distribution 3")

ax3 = f.add_subplot(2,4,8)
plt.hist(histo_3, bins='fd', color = "peru", edgecolor='white', linewidth=1.2)
plt.title("Distribution 4")

plt.tight_layout()
plt.show()

The only way to make it look good is to have two separated figures such as:

2figures_better_but_not_saving

histo_1 = np.random.choice(500, 100, replace=True)
histo_2 = np.random.choice(250, 7000, replace=True)
histo_3 = np.random.choice(150, 1500, replace=True)
histo_4 = np.random.choice(2000, 250, replace=True)

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]


f = plt.figure(figsize = (14, 15))
sn.set()
sn.color_palette("hls", 8)

ax = f.add_subplot(1,3,1)
plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
plt.title("Distribution")

ax = f.add_subplot(1,3,2)
plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
plt.title("Distribution")

ax = f.add_subplot(1,3,3)
plt.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
plt.title("Distribution")

plt.tight_layout()
plt.show()


f = plt.figure(figsize = (14, 8))

ax = f.add_subplot(1,4,1)
plt.hist(histo_1, bins='fd', color = "cornflowerblue", edgecolor='white', linewidth=1.2)
plt.title("Distribution 1")

ax1 = f.add_subplot(1,4,2)
plt.hist(histo_2, bins='fd', color = "indianred", edgecolor='white', linewidth=1.2)
plt.title("Distribution 2")

ax2 = f.add_subplot(1,4,3)
plt.hist(histo_3, bins='fd', color = "seagreen", edgecolor='white', linewidth=1.2)
plt.title("Distribution 3")

ax3 = f.add_subplot(1,4,4)
plt.hist(histo_3, bins='fd', color = "peru", edgecolor='white', linewidth=1.2)
plt.title("Distribution 4")

plt.tight_layout()
plt.show()

Therefore, I need to find a way to reduce the space between the charts/histograms or a way to save or stitch the two figures together in one file.

Does anyone has a suggestion ?

Thank you


Solution

  • Using Gridspec, I set up a subplot with two rows and four columns, adjusted the height between the subplots, and adjusted the overall height and bottom of the subplots to their values. This would keep the saved image in one piece, and I omitted further margins in the save parameters.

    import matplotlib.pyplot as plt
    import seaborn as sn
    from matplotlib.gridspec import GridSpec
    
    histo_1 = np.random.choice(500, 100, replace=True)
    histo_2 = np.random.choice(250, 7000, replace=True)
    histo_3 = np.random.choice(150, 1500, replace=True)
    histo_4 = np.random.choice(2000, 250, replace=True)
    
    labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
    sizes = [15, 30, 45, 10]
    
    fig = plt.figure(figsize = (14, 14))# ,constrained_layout=True
    sn.set()
    sn.color_palette("hls", 8)
    
    gs = GridSpec(nrows=2, ncols=4, hspace=0, figure=fig) #height_ratios=[1.0, 0.40], 
    fig.subplots_adjust(top=0.65, bottom=0.25, hspace=0.0)
    
    ax1 = fig.add_subplot(gs[0,0])
    ax1.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
    ax1.set_title("Distribution")
    
    ax2 = fig.add_subplot(gs[0,1])
    ax2.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
    ax2.set_title("Distribution")
    
    ax3 = fig.add_subplot(gs[0,2])
    ax3.pie(sizes, labels = labels, autopct='%1.1f%%', textprops={'fontsize': 13})
    ax3.set_title("Distribution")
    
    ax4 = fig.add_subplot(gs[1,0])
    ax4.hist(histo_1, bins='fd', color = "cornflowerblue", edgecolor='white', linewidth=1.2)
    ax4.set_title("Distribution 1")
    
    ax5 = fig.add_subplot(gs[1,1])
    ax5.hist(histo_2, bins='fd', color = "indianred", edgecolor='white', linewidth=1.2)
    ax5.set_title("Distribution 2")
    
    ax6 = fig.add_subplot(gs[1,2])
    ax6.hist(histo_3, bins='fd', color = "seagreen", edgecolor='white', linewidth=1.2)
    ax6.set_title("Distribution 3")
    
    ax6 = fig.add_subplot(gs[1,3])
    ax6.hist(histo_3, bins='fd', color = "peru", edgecolor='white', linewidth=1.2)
    ax6.set_title("Distribution 4")
    
    #plt.tight_layout()
    plt.savefig('./data/combine_plot.png', bbox_inches='tight')
    plt.show()
    

    enter image description here